Java: what is the correct way to guarantee a non-final reference field will never be read as null? -
i'm trying solve simple problem , falling java memory model rabbit hole.
what simplest and/or efficient (judgement call here), race-free (precisely defined according jmm) way write java class containing non-final reference field initialized non-null value in constructor , subsequently never changed, such no subsequent access of field other thread can see non-null value?
broken starting example:
public class holder { private object value; public holder(object value) { if (value == null) throw nullpointerexception(); this.value = value; } public object getvalue() { // return null! return this.value; } }
and according this post, marking field volatile
doesn't work!
public class holder { private volatile object value; public holder(object value) { if (value == null) throw nullpointerexception(); this.value = value; } public object getvalue() { // still return null!! return this.value; } }
is best can do??
public class holder { private object value; public holder(object value) { if (value == null) throw nullpointerexception(); synchronized (this) { this.value = value; } } public synchronized object getvalue() { return this.value; } }
ok this?
public class holder { private object value; public holder(object value) { if (value == null) throw nullpointerexception(); this.value = value; synchronized (this) { } } public synchronized object getvalue() { return this.value; } }
side note: related question asks how without using volatile
or synchronization, of course impossible.
the problem trying solve called safe publication , there exist benchmarks best performant solution. personally, prefer holder pattern performs best. define publisher
class single generic field:
class publisher<t> { private final t value; private publisher(t value) { this.value = value; } public static <s> s publish(s value) { return new publisher<s>(value).value; } }
you can create instance via:
holder holder = publisher.publish(new holder(value));
since holder
dereferenced via final
field, guaranteed initialized jmm after reading same final field.
if usage of class, should of course add convenience factory class , make constructor private
avoid unsafe construction.
note performs modern vms erase object allocation after applying escape anaysis. minimal performance overhead comes remaining memory barriers in generated machine code required safely publish instance.
note: holder pattern not confused example class being called holder
. publisher
implements holder pattern in example.
Comments
Post a Comment