@Gil Tene, thanks for your response. But in other cases where non-final fields are involved, e.g. if p.x was a > Foo with a non-final field y with a getter, p.x.getY() may return an > uninitialized value after the get() returns a non-null p. >
So, it means that in this case: class Foo { public Foo(int i) { x = i;} public int x; } ConcurrentHashMap<Integer, Foo> x = new ConcurrentHashMap<>(); new Thread(() -> { // Thread 1 x.put(1, new Foo(1)); // 1 }).start(); new Thread(() -> { // Thread 2 Foo p = x.get(1); // 2 if(p != null){ // 3 print(p.x); // 4 } }).start(); the Thread 2 can read 0 in the line (4). I cannot agree with that because: 1. Note that a putting element to the hashmap stores a value to the field annotated as volatile: https://github.com/bpupadhyaya/openjdk-8/blob/master/jdk/src/share/classes/java/util/concurrent/ConcurrentHashMap.java#L622 2. Note that a getting element from the hashmap reads a value from the field annoated as volatile: https://github.com/bpupadhyaya/openjdk-8/blob/master/jdk/src/share/classes/java/util/concurrent/ConcurrentHashMap.java#L622 So, if the second thread obeserves not null value in the 3 line it means there is a synchronization-with relation betweeen storing a Foo instance to value field in hashmap and reading from them. In a result we have a HB relation: new Foo(1) --HB--> store to volatile value --HB--> read from volatile value --HB--> read Foo.x field We have a such chain of HB relations because it is a transitive close of PO and SW orders: <https://shipilev.net/blog/2014/jmm-pragmatics/page-077.png> W dniu sobota, 17 listopada 2018 08:52:53 UTC+1 użytkownik Gil Tene napisał: > > Well, "yes, sort of". > > Your example works for String, because it is immutable. > > Specifically, there is a happens-before relationship between the > constructor's initialization of the final fields of the String and the > subsequent publishing store of the result of the constructor. > > However, non-final fields have no such happens-before relationship with > the publishing store. E.g. the cached hash field in String > <https://github.com/bpupadhyaya/openjdk-8/blob/master/jdk/src/share/classes/java/lang/String.java#L117> > may > or may not be have been initialized when p.x is read. > > This [race on hash field initialization] has no visible side effect > because of how the hash field is used in String: it caches the hash code, > and will freshly compute the hash from the immutable char[] if the field > holds a 0. So even if the initialization races with a call to hashCode() > <https://github.com/bpupadhyaya/openjdk-8/blob/master/jdk/src/share/classes/java/lang/String.java#L1452> > [e.g. > a call to hashcode happens on another thread before the hash field is > initialized, and the initialization overwrites the cached value with a 0], > all that would happen is a recomputation of the same hash. The value > returned by hashCode() won't change. > > But in other cases where non-final fields are involved, e.g. if p.x was a > Foo with a non-final field y with a getter, p.x.getY() may return an > uninitialized value after the get() returns a non-null p. > > On Friday, November 16, 2018 at 3:59:47 AM UTC-8, John Hening wrote: >> >> Hello, let's look at: >> >> >> >> class P { public String x; >> } >> >> ConcurrentHashMap<Integer, P> x = new ConcurrentHashMap<>(); >> >> new Thread(() -> { // Thread 1 >> x.put(1, new String("x")); // 1 >> }).start(); >> >> new Thread(() -> { // Thread 2 >> P p = x.get(1); // 2 >> if(p != null){ >> print(p.x); // 4 >> } >> }).start(); >> >> >> >> >> If thread 2 observes p != null is it guaranteed by JMM that p.x is >> initialized? For my eye, yes, because: >> >> Let's assume a such execution when p != null was true. It means that >> there is a synchronize-with relation between x.put(1, new String("x")); >> --sw--> x.get(). >> Putting and getting an element from ConcurrentHashMap contain >> synchronization access (and, actually, synchronization-with is between >> them). >> >> In a result, there is a chain of happens-before relation: >> >> tmp = new String("x") --hb--> x.put(1, tmp) --hb--> x.get(1) --hb--> >> read(p.x) >> >> >> >> >> Yes? >> >> >> >> >> >> -- You received this message because you are subscribed to the Google Groups "mechanical-sympathy" group. To unsubscribe from this group and stop receiving emails from it, send an email to mechanical-sympathy+unsubscr...@googlegroups.com. For more options, visit https://groups.google.com/d/optout.