114 |
|
*/ |
115 |
|
static final int MAX_SEGMENTS = 1 << 16; // slightly conservative |
116 |
|
|
117 |
+ |
/** |
118 |
+ |
* Number of unsynchronized retries in size and containsValue |
119 |
+ |
* methods before resorting to locking. This is used to avoid |
120 |
+ |
* unbounded retries if tables undergo continuous modification |
121 |
+ |
* which would make it impossible to obtain an accurate result. |
122 |
+ |
*/ |
123 |
+ |
static final int RETRIES_BEFORE_LOCK = 2; |
124 |
+ |
|
125 |
|
/* ---------------- Fields -------------- */ |
126 |
|
|
127 |
|
/** |
173 |
|
/* ---------------- Inner Classes -------------- */ |
174 |
|
|
175 |
|
/** |
176 |
+ |
* ConcurrentHashMap list entry. Note that this is never exported |
177 |
+ |
* out as a user-visible Map.Entry. |
178 |
+ |
* |
179 |
+ |
* Because the value field is volatile, not final, it is legal wrt |
180 |
+ |
* the Java Memory Model for an unsynchronized reader to see null |
181 |
+ |
* instead of initial value when read via a data race. Although a |
182 |
+ |
* reordering leading to this is not likely to ever actually |
183 |
+ |
* occur, the Segment.readValueUnderLock method is used as a |
184 |
+ |
* backup in case a null (pre-initialized) value is ever seen in |
185 |
+ |
* an unsynchronized access method. |
186 |
+ |
*/ |
187 |
+ |
static final class HashEntry<K,V> { |
188 |
+ |
final K key; |
189 |
+ |
final int hash; |
190 |
+ |
volatile V value; |
191 |
+ |
final HashEntry<K,V> next; |
192 |
+ |
|
193 |
+ |
HashEntry(K key, int hash, HashEntry<K,V> next, V value) { |
194 |
+ |
this.key = key; |
195 |
+ |
this.hash = hash; |
196 |
+ |
this.next = next; |
197 |
+ |
this.value = value; |
198 |
+ |
} |
199 |
+ |
} |
200 |
+ |
|
201 |
+ |
/** |
202 |
|
* Segments are specialized versions of hash tables. This |
203 |
|
* subclasses from ReentrantLock opportunistically, just to |
204 |
|
* simplify some locking and avoid separate construction. |
252 |
|
* Number of updates that alter the size of the table. This is |
253 |
|
* used during bulk-read methods to make sure they see a |
254 |
|
* consistent snapshot: If modCounts change during a traversal |
255 |
< |
* of segments computing size or checking contatinsValue, then |
255 |
> |
* of segments computing size or checking containsValue, then |
256 |
|
* we might have an inconsistent view of state so (usually) |
257 |
|
* must retry. |
258 |
|
*/ |
551 |
|
} |
552 |
|
} |
553 |
|
|
520 |
– |
/** |
521 |
– |
* ConcurrentHashMap list entry. Note that this is never exported |
522 |
– |
* out as a user-visible Map.Entry |
523 |
– |
*/ |
524 |
– |
static final class HashEntry<K,V> { |
525 |
– |
final K key; |
526 |
– |
final int hash; |
527 |
– |
volatile V value; |
528 |
– |
final HashEntry<K,V> next; |
529 |
– |
|
530 |
– |
HashEntry(K key, int hash, HashEntry<K,V> next, V value) { |
531 |
– |
this.key = key; |
532 |
– |
this.hash = hash; |
533 |
– |
this.next = next; |
534 |
– |
this.value = value; |
535 |
– |
} |
536 |
– |
} |
554 |
|
|
555 |
|
|
556 |
|
/* ---------------- Public operations -------------- */ |
674 |
|
long sum = 0; |
675 |
|
long check = 0; |
676 |
|
int[] mc = new int[segments.length]; |
677 |
< |
// Try at most twice to get accurate count. On failure due to |
677 |
> |
// Try a few times to get accurate count. On failure due to |
678 |
|
// continuous async changes in table, resort to locking. |
679 |
< |
for (int k = 0; k < 2; ++k) { |
679 |
> |
for (int k = 0; k < RETRIES_BEFORE_LOCK; ++k) { |
680 |
|
check = 0; |
681 |
|
sum = 0; |
682 |
|
int mcsum = 0; |
762 |
|
final Segment[] segments = this.segments; |
763 |
|
int[] mc = new int[segments.length]; |
764 |
|
|
765 |
< |
// Try at most twice without locking |
766 |
< |
for (int k = 0; k < 2; ++k) { |
765 |
> |
// Try a few times without locking |
766 |
> |
for (int k = 0; k < RETRIES_BEFORE_LOCK; ++k) { |
767 |
|
int sum = 0; |
768 |
|
int mcsum = 0; |
769 |
|
for (int i = 0; i < segments.length; ++i) { |