java - Are Immutable objects immune to improper publication? -


it example jcip.

public class unsafe {     // unsafe publication      public holder holder;      public void initialize() {         holder = new holder(42);     } }  public class holder {     private int n;      public holder(int n) {         this.n = n;     }     public void assertsanity() {         if (n != n) {             throw new assertionerror("this statement false.");         }     } } 

on page 34:

[15] problem here not holder class itself, holder not published. however, holder can made immune improper publication declaring n field final, make holder immutable;

and this answer:

the specification final (see @andersoj's answer) guarantees when constructor returns, final field have been initialized (as visible threads).

from wiki:

for example, in java if call constructor has been inlined shared variable may updated once storage has been allocated before inlined constructor initializes object

my question is:

because : (could wrong, don't know.)

a) shared variable may updated before inlined constructor initializes object.

b) final field guaranteed initialized (as visible threads) when constructor returns.

is possible thread sees default value of holder.n? (i.e. thread gets reference holder before holder constructor returns.)

if so, how explain statement below?

holder can made immune improper publication declaring n field final, make holder immutable

edit: jcip. definition of immutable object:

an object immutable if:
x state cannot modified after construction;

x fields final;[12] and

x constructed (the reference not escape during construction).

so, definition, immutable objects don't have "this reference escaping" problems. right?

but suffer out-of-order writes in double-checked-locking pattern if not declared volatile?

an immutable object, e.g. string, appears have same state readers, regardless how reference obtained, improper synchronization , lack of happens-before relationship.

this achieved final field semantics introduced in java 5. data access through final field has stronger memory semantics, defined in jls-17.5.1

in terms of compiler reordering , memory barriers, there more constraints when dealing final fields, see jsr-133 cookbook. reordering worried won't happen.

and yes -- double-checked locking can done through final field in wrapper; no volatile required! approach not faster, because 2 reads needed.


note semantics applies individual final fields, not entire object whole. example, string contains mutable field hash; nevertheless, string considered immutable because public behavior based on final fields.

a final field can point mutable object. example, string.value char[] mutable. it's impractical require immutable object tree of final fields.

final char[] value;  public string(args) {     this.value = createfrom(args); } 

as long don't modify content of value after constructor exit, it's fine.

we can modify content of value in constructor in order, doesn't matter.

public string(args) {     this.value = new char[1];     this.value[0] = 'x';  // modify after field assigned. } 

another example

final map map; list list;  public foo() {     map = new hashmap();     list = listof("etc", "etc", "etc");     map.put("etc", list) } 

any access through final field appear immutable, e.g. foo.map.get("etc").get(2).

access not through final field not -- foo.list.get(2) not safe through improper publication, though reads same destination.


those design motivations. let's see how jls formalizes in jls-17.5.1

a freeze action defined @ constructor exit, apposed @ assignment of final field. allows write anywhere inside constructor populate internal state.

the usual problem of unsafe publication lack of happens-before (hb) relationship. if read sees write, establishes nothing w.r.t other actions. if volatile read sees volatile write, jmm establishes hb , order among many actions.

the final field semantics wants same thing, normal reads , writes, is, through unsafe publications. that, memory chain (mc) order added between write seen read.

a deferences() order limits semantics accesses through final field.

let's revisit foo example see how works

tmp = new foo()      [w] write list @ index 2      [f] freeze @ constructor exit  shared = tmp;   [a]  normal write  // thread  foo = shared;   [r0] normal read  if(foo!=null) // [r0] sees [a], therefore mc(a, r0)      map = foo.map;          [r1] reads final field      map.get("etc").get(2)   [r2] 

we have

hb(w, f), hb(f, a), mc(a, r1), , dereferences(r1, r2) 

therefore w visible r2.


essentially, through foo wrapper, map (which mutable in itself) published safely though unsafe publication... if makes sense.

can use wrapper establish final field semantics discard it? like

foo foo = new foo();   // [w] [f]  shared_map = foo.map;  // [a] 

interestingly, jls contains enough clauses exclude such use case. guess it's weakened more inner-thread optimizations permitted, final fields.


note if this leaked before freeze action, final field semantics not guaranteed.

however, can safely leak this in constructor after freeze action, constructor chaining.

-- class bar  final int x;  bar(int x, int ignore) {     this.x = x;  // assign final }  // [f] freeze action on this.x  public bar(int x) {      this(x, 0);     // [f] reached!     leak(this);  } 

this safe far x concerned; freeze action on x defined @ exist of constructor in x assigned. designed safely leak this.


Comments

Popular posts from this blog

Delphi XE2 Indy10 udp client-server interchange using SendBuffer-ReceiveBuffer -

Qt ActiveX WMI QAxBase::dynamicCallHelper: ItemIndex(int): No such property in -

Enable autocomplete or intellisense in Atom editor for PHP -