52
52
* {@linkplain SoftReference soft entry references}.
53
53
*
54
54
* @author Phillip Webb
55
+ * @author Juergen Hoeller
55
56
* @since 3.2
56
57
* @param <K> the key type
57
58
* @param <V> the value type
@@ -94,7 +95,7 @@ public class ConcurrentReferenceHashMap<K, V> extends AbstractMap<K, V> implemen
94
95
/**
95
96
* Late binding entry set.
96
97
*/
97
- private Set <Map .Entry <K , V >> entrySet ;
98
+ private volatile Set <Map .Entry <K , V >> entrySet ;
98
99
99
100
100
101
/**
@@ -163,8 +164,8 @@ public ConcurrentReferenceHashMap(int initialCapacity, float loadFactor, int con
163
164
* @param referenceType the reference type used for entries (soft or weak)
164
165
*/
165
166
@ SuppressWarnings ("unchecked" )
166
- public ConcurrentReferenceHashMap (int initialCapacity , float loadFactor , int concurrencyLevel ,
167
- ReferenceType referenceType ) {
167
+ public ConcurrentReferenceHashMap (
168
+ int initialCapacity , float loadFactor , int concurrencyLevel , ReferenceType referenceType ) {
168
169
169
170
Assert .isTrue (initialCapacity >= 0 , "Initial capacity must not be negative" );
170
171
Assert .isTrue (loadFactor > 0f , "Load factor must be positive" );
@@ -211,7 +212,7 @@ protected ReferenceManager createReferenceManager() {
211
212
* @return the resulting hash code
212
213
*/
213
214
protected int getHash (Object o ) {
214
- int hash = o == null ? 0 : o .hashCode ();
215
+ int hash = ( o != null ? o .hashCode () : 0 );
215
216
hash += (hash << 15 ) ^ 0xffffcd7d ;
216
217
hash ^= (hash >>> 10 );
217
218
hash += (hash << 3 );
@@ -240,8 +241,8 @@ public boolean containsKey(Object key) {
240
241
}
241
242
242
243
private Entry <K , V > getEntryIfAvailable (Object key ) {
243
- Reference <K , V > reference = getReference (key , Restructure .WHEN_NECESSARY );
244
- return (reference != null ? reference .get () : null );
244
+ Reference <K , V > ref = getReference (key , Restructure .WHEN_NECESSARY );
245
+ return (ref != null ? ref .get () : null );
245
246
}
246
247
247
248
/**
@@ -269,13 +270,13 @@ public V putIfAbsent(K key, V value) {
269
270
private V put (final K key , final V value , final boolean overwriteExisting ) {
270
271
return doTask (key , new Task <V >(TaskOption .RESTRUCTURE_BEFORE , TaskOption .RESIZE ) {
271
272
@ Override
272
- protected V execute (Reference <K , V > reference , Entry <K , V > entry , Entries entries ) {
273
+ protected V execute (Reference <K , V > ref , Entry <K , V > entry , Entries entries ) {
273
274
if (entry != null ) {
274
- V previousValue = entry .getValue ();
275
+ V oldValue = entry .getValue ();
275
276
if (overwriteExisting ) {
276
277
entry .setValue (value );
277
278
}
278
- return previousValue ;
279
+ return oldValue ;
279
280
}
280
281
entries .add (value );
281
282
return null ;
@@ -287,9 +288,9 @@ protected V execute(Reference<K, V> reference, Entry<K, V> entry, Entries entrie
287
288
public V remove (Object key ) {
288
289
return doTask (key , new Task <V >(TaskOption .RESTRUCTURE_AFTER , TaskOption .SKIP_IF_EMPTY ) {
289
290
@ Override
290
- protected V execute (Reference <K , V > reference , Entry <K , V > entry ) {
291
+ protected V execute (Reference <K , V > ref , Entry <K , V > entry ) {
291
292
if (entry != null ) {
292
- reference .release ();
293
+ ref .release ();
293
294
return entry .value ;
294
295
}
295
296
return null ;
@@ -301,9 +302,9 @@ protected V execute(Reference<K, V> reference, Entry<K, V> entry) {
301
302
public boolean remove (Object key , final Object value ) {
302
303
return doTask (key , new Task <Boolean >(TaskOption .RESTRUCTURE_AFTER , TaskOption .SKIP_IF_EMPTY ) {
303
304
@ Override
304
- protected Boolean execute (Reference <K , V > reference , Entry <K , V > entry ) {
305
+ protected Boolean execute (Reference <K , V > ref , Entry <K , V > entry ) {
305
306
if (entry != null && ObjectUtils .nullSafeEquals (entry .getValue (), value )) {
306
- reference .release ();
307
+ ref .release ();
307
308
return true ;
308
309
}
309
310
return false ;
@@ -315,7 +316,7 @@ protected Boolean execute(Reference<K, V> reference, Entry<K, V> entry) {
315
316
public boolean replace (K key , final V oldValue , final V newValue ) {
316
317
return doTask (key , new Task <Boolean >(TaskOption .RESTRUCTURE_BEFORE , TaskOption .SKIP_IF_EMPTY ) {
317
318
@ Override
318
- protected Boolean execute (Reference <K , V > reference , Entry <K , V > entry ) {
319
+ protected Boolean execute (Reference <K , V > ref , Entry <K , V > entry ) {
319
320
if (entry != null && ObjectUtils .nullSafeEquals (entry .getValue (), oldValue )) {
320
321
entry .setValue (newValue );
321
322
return true ;
@@ -329,11 +330,11 @@ protected Boolean execute(Reference<K, V> reference, Entry<K, V> entry) {
329
330
public V replace (K key , final V value ) {
330
331
return doTask (key , new Task <V >(TaskOption .RESTRUCTURE_BEFORE , TaskOption .SKIP_IF_EMPTY ) {
331
332
@ Override
332
- protected V execute (Reference <K , V > reference , Entry <K , V > entry ) {
333
+ protected V execute (Reference <K , V > ref , Entry <K , V > entry ) {
333
334
if (entry != null ) {
334
- V previousValue = entry .getValue ();
335
+ V oldValue = entry .getValue ();
335
336
entry .setValue (value );
336
- return previousValue ;
337
+ return oldValue ;
337
338
}
338
339
return null ;
339
340
}
@@ -370,11 +371,23 @@ public int size() {
370
371
}
371
372
372
373
@ Override
373
- public Set <java .util .Map .Entry <K , V >> entrySet () {
374
- if (this .entrySet == null ) {
375
- this .entrySet = new EntrySet ();
374
+ public boolean isEmpty () {
375
+ for (Segment segment : this .segments ) {
376
+ if (segment .getCount () > 0 ) {
377
+ return false ;
378
+ }
379
+ }
380
+ return true ;
381
+ }
382
+
383
+ @ Override
384
+ public Set <Map .Entry <K , V >> entrySet () {
385
+ Set <Map .Entry <K , V >> entrySet = this .entrySet ;
386
+ if (entrySet == null ) {
387
+ entrySet = new EntrySet ();
388
+ this .entrySet = entrySet ;
376
389
}
377
- return this . entrySet ;
390
+ return entrySet ;
378
391
}
379
392
380
393
private <T > T doTask (Object key , Task <T > task ) {
@@ -485,8 +498,8 @@ public <T> T doTask(final int hash, final Object key, final Task<T> task) {
485
498
try {
486
499
final int index = getIndex (hash , this .references );
487
500
final Reference <K , V > head = this .references [index ];
488
- Reference <K , V > reference = findInChain (head , key , hash );
489
- Entry <K , V > entry = (reference != null ? reference .get () : null );
501
+ Reference <K , V > ref = findInChain (head , key , hash );
502
+ Entry <K , V > entry = (ref != null ? ref .get () : null );
490
503
Entries entries = new Entries () {
491
504
@ Override
492
505
public void add (V value ) {
@@ -497,7 +510,7 @@ public void add(V value) {
497
510
Segment .this .count ++;
498
511
}
499
512
};
500
- return task .execute (reference , entry , entries );
513
+ return task .execute (ref , entry , entries );
501
514
}
502
515
finally {
503
516
unlock ();
@@ -531,19 +544,18 @@ public void clear() {
531
544
* @param allowResize if resizing is permitted
532
545
*/
533
546
protected final void restructureIfNecessary (boolean allowResize ) {
534
- boolean needsResize = (( this .count > 0 ) && ( this .count >= this .resizeThreshold ) );
535
- Reference <K , V > reference = this .referenceManager .pollForPurge ();
536
- if (( reference != null ) || (needsResize && allowResize )) {
547
+ boolean needsResize = (this .count > 0 && this .count >= this .resizeThreshold );
548
+ Reference <K , V > ref = this .referenceManager .pollForPurge ();
549
+ if (ref != null || (needsResize && allowResize )) {
537
550
lock ();
538
551
try {
539
552
int countAfterRestructure = this .count ;
540
-
541
553
Set <Reference <K , V >> toPurge = Collections .emptySet ();
542
- if (reference != null ) {
554
+ if (ref != null ) {
543
555
toPurge = new HashSet <Reference <K , V >>();
544
- while (reference != null ) {
545
- toPurge .add (reference );
546
- reference = this .referenceManager .pollForPurge ();
556
+ while (ref != null ) {
557
+ toPurge .add (ref );
558
+ ref = this .referenceManager .pollForPurge ();
547
559
}
548
560
}
549
561
countAfterRestructure -= toPurge .size ();
@@ -559,22 +571,22 @@ protected final void restructureIfNecessary(boolean allowResize) {
559
571
}
560
572
561
573
// Either create a new table or reuse the existing one
562
- Reference <K , V >[] restructured = (resizing ? createReferenceArray (restructureSize ) : this .references );
574
+ Reference <K , V >[] restructured =
575
+ (resizing ? createReferenceArray (restructureSize ) : this .references );
563
576
564
577
// Restructure
565
578
for (int i = 0 ; i < this .references .length ; i ++) {
566
- reference = this .references [i ];
579
+ ref = this .references [i ];
567
580
if (!resizing ) {
568
581
restructured [i ] = null ;
569
582
}
570
- while (reference != null ) {
571
- if (!toPurge .contains (reference ) && (reference .get () != null )) {
572
- int index = getIndex (reference .getHash (), restructured );
583
+ while (ref != null ) {
584
+ if (!toPurge .contains (ref ) && (ref .get () != null )) {
585
+ int index = getIndex (ref .getHash (), restructured );
573
586
restructured [index ] = this .referenceManager .createReference (
574
- reference .get (), reference .getHash (),
575
- restructured [index ]);
587
+ ref .get (), ref .getHash (), restructured [index ]);
576
588
}
577
- reference = reference .getNext ();
589
+ ref = ref .getNext ();
578
590
}
579
591
}
580
592
@@ -590,8 +602,8 @@ protected final void restructureIfNecessary(boolean allowResize) {
590
602
}
591
603
}
592
604
593
- private Reference <K , V > findInChain (Reference <K , V > reference , Object key , int hash ) {
594
- Reference <K , V > currRef = reference ;
605
+ private Reference <K , V > findInChain (Reference <K , V > ref , Object key , int hash ) {
606
+ Reference <K , V > currRef = ref ;
595
607
while (currRef != null ) {
596
608
if (currRef .getHash () == hash ) {
597
609
Entry <K , V > entry = currRef .get ();
@@ -744,24 +756,24 @@ public boolean hasOption(TaskOption option) {
744
756
745
757
/**
746
758
* Execute the task.
747
- * @param reference the found reference or {@code null}
759
+ * @param ref the found reference or {@code null}
748
760
* @param entry the found entry or {@code null}
749
761
* @param entries access to the underlying entries
750
762
* @return the result of the task
751
763
* @see #execute(Reference, Entry)
752
764
*/
753
- protected T execute (Reference <K , V > reference , Entry <K , V > entry , Entries entries ) {
754
- return execute (reference , entry );
765
+ protected T execute (Reference <K , V > ref , Entry <K , V > entry , Entries entries ) {
766
+ return execute (ref , entry );
755
767
}
756
768
757
769
/**
758
770
* Convenience method that can be used for tasks that do not need access to {@link Entries}.
759
- * @param reference the found reference or {@code null}
771
+ * @param ref the found reference or {@code null}
760
772
* @param entry the found entry or {@code null}
761
773
* @return the result of the task
762
774
* @see #execute(Reference, Entry, Entries)
763
775
*/
764
- protected T execute (Reference <K , V > reference , Entry <K , V > entry ) {
776
+ protected T execute (Reference <K , V > ref , Entry <K , V > entry ) {
765
777
return null ;
766
778
}
767
779
}
@@ -801,12 +813,12 @@ public Iterator<Map.Entry<K, V>> iterator() {
801
813
802
814
@ Override
803
815
public boolean contains (Object o ) {
804
- if (o != null && o instanceof Map .Entry <?, ?>) {
805
- Map .Entry <?, ?> entry = (java . util . Map .Entry <?, ?>) o ;
806
- Reference <K , V > reference = ConcurrentReferenceHashMap .this .getReference (entry .getKey (), Restructure .NEVER );
807
- Entry <K , V > other = (reference != null ? reference .get () : null );
808
- if (other != null ) {
809
- return ObjectUtils .nullSafeEquals (entry .getValue (), other .getValue ());
816
+ if (o instanceof Map .Entry <?, ?>) {
817
+ Map .Entry <?, ?> entry = (Map .Entry <?, ?>) o ;
818
+ Reference <K , V > ref = ConcurrentReferenceHashMap .this .getReference (entry .getKey (), Restructure .NEVER );
819
+ Entry <K , V > otherEntry = (ref != null ? ref .get () : null );
820
+ if (otherEntry != null ) {
821
+ return ObjectUtils .nullSafeEquals (otherEntry .getValue (), otherEntry .getValue ());
810
822
}
811
823
}
812
824
return false ;
0 commit comments