@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.

Reply via email to