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 specifica 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 you size() call. The unlock() at e.g. the bottom of seg.put() 
creates enough ordering on the modifying side.

A critical thing to keep in mind when reading JDK code like this is that 
the you should not necessarily assume that your code doing the same thing 
would be safe from an ordering perspective. JDK code is special, because it 
*knows* what JVMs it ships with. Since j.u.c.ConcurrentHashMap in OpenJDK 7 
is part of the JDK, it can make certain assumptions about the 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 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