Thanks for the detailed reply. 
Yes, JDK code is special.  From an ordering  perspective, the segmentAt() 
does a volatile read and ensures visibility. 
However from happen-before perspective, I cannot find happen-before 
relation between seg.count read action with seg.count write action. 

thread 1                                                                   
 thread 2
--------------------------------------------------------------------------------------
1. segment reference volatile write                   |       3. segment 
reference volatile read
2. seg.count write                                              |       4. 
seg.count read

It's obvious that action 1 has a happen-before relation with action 3.
But there's no happen-before relation between action 2 and action 4.
Am I wrong? Or I just should not consider it from the happen-before 
perspective because the JDK code is special?

On Monday, September 18, 2017 at 11:31:52 PM UTC+8, Gil Tene wrote:
>
> In the presence of concurrent modification, size() can be stale by 
> definition, since the modification could occur between size() establishing 
> a notion of what size is and your next operation that might assume the size 
> is somehow representative of the current state of the table.
>
> When no concurrent modification exists between your call into size() and 
> whatever the next thing you do that depends on that size is, the size will 
> be up-to-date. The thing that achieves that in the OpenJDK 7 variant 
> <http://grepcode.com/file/repository.grepcode.com/java/root/jdk/openjdk/7-b147/java/util/concurrent/ConcurrentHashMap.java#ConcurrentHashMap.size%28%29>
>  
> is the fact that segmentAt() does a volatile read, which is sufficient (at 
> least in the specific OpenJDK 7 JVM implementation) to establish a LoadLoad 
> ahead of the following reads of seg.count and seg.modCount to reflect 
> external modifications that (by other ordering rules) occurred prior to 
> your size() call. The unlock() at e.g. the bottom of seg.put() creates 
> enough ordering on the modifying side after the changes to seg.count and 
> seg.modCount.
>
> A critical thing to keep in mind when reading JDK code like this is that 
> the you should not necessarily assume that your code can do the same thing 
> safely from an ordering perspective. JDK code is special because it *knows* 
> what JVMs it ships with, and can validly make assumptions about the JVMs 
> behavior. Since j.u.c.ConcurrentHashMap in OpenJDK 7 is part of the JDK, it 
> can make certain assumptions about the OpenJDK 7 JVM's handling of ordering 
> that may be stronger than the JMM guarantees. E.g. it could assume that the 
> *sufficient* (but not fully required by the JMM) ordering rules in 
> http://gee.cs.oswego.edu/dl/jmm/cookbook.html are actually implemented, 
> based on knowledge of the specific JVM that ships with the JDK code. E.g. a 
> JVM that satisfies these rules: 
>
>
> <https://lh3.googleusercontent.com/--z6nET8Y_rI/Wb_j4Ym4AHI/AAAAAAAAATM/9hYYa3Llne0ibtkz4B1jm_7VZU-vXYI-wCLcBGAs/s1600/JMMCookbookTable.png>
>
> Will meet the JMM ordering requirements between volatile loads and stores, 
> regular loads and stores, and monitor enters and exits. But that doesn't 
> actually mean that all JVMs (and future JDKs you may run on) will actually 
> follow these rules. They may find some way to meet the JMM requirements 
> without following these rules to the letter. E.g. they may apply the 
> ordering between specific sets of fields (rather than globally, across all 
> fields as stated in this matrix), and still meet the JMM without enforcing 
> a LoadLoad between any volatile load and any field load.
>
>
> On Sunday, September 17, 2017 at 11:54:45 PM UTC-7, yang liu wrote:
>>
>> "...useful only when a map is not undergoing concurrent updates in other 
>> threads..." 
>> The size() method sums the segment field "modCount" twice and compares 
>> the result to ensure no concurrent updates in other threads.
>> If there's concurrent updates, the size() method resort to locking 
>> segments. So the size() method tries to get the mostly updated 
>> result even if after the result returns the result may already be stale. 
>> In java1.6 field "count" has volatile present and "modCount" 
>> field read has happen-before relation with "count" write, so the sum of 
>> "count" can has mostly updated result. But that's not the case for java 1.7.
>> In java1.7 the no volatile present field "modCount" and "count" may fail 
>> to get mostly updated value.
>>
>> On Monday, September 18, 2017 at 1:46:34 PM UTC+8, Nikolay Tsankov wrote:
>>>
>>> * Bear in mind that the results of aggregate status methods including
>>> * {@code size}, {@code isEmpty}, and {@code containsValue} are typically
>>> * useful only when a map is not undergoing concurrent updates in other 
>>> threads.
>>> * Otherwise the results of these methods reflect transient states
>>> * that may be adequate for monitoring or estimation purposes, but not
>>> * for program control.
>>>
>>>
>>> On Mon, Sep 18, 2017 at 5:18 AM, yang liu <[email protected]> wrote:
>>>
>>>> Recently I studied the source code of ConcurrentHashMap. 
>>>>
>>>> In java 1.7, the segment field "count" got no volatile modifiers which 
>>>> is different from java 1.6. 
>>>>
>>>> Is possible the size() method could read stale value through race read?
>>>>
>>>>
>>>> -- 
>>>> 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.
>>>>
>>>
>>>

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

Reply via email to