@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 [email protected].
For more options, visit https://groups.google.com/d/optout.