1
1
/*
2
- * Copyright 2002-2012 the original author or authors.
2
+ * Copyright 2002-2013 the original author or authors.
3
3
*
4
4
* Licensed under the Apache License, Version 2.0 (the "License");
5
5
* you may not use this file except in compliance with the License.
48
48
* references at any time, so it may appear that an unknown thread is silently removing
49
49
* entries.
50
50
*
51
- * <p>If not explicitly specified this implementation will use
51
+ * <p>If not explicitly specified, this implementation will use
52
52
* {@linkplain SoftReference soft entry references}.
53
53
*
54
54
* @param <K> The key type
55
55
* @param <V> The value type
56
56
* @author Phillip Webb
57
57
* @since 3.2
58
58
*/
59
- public class ConcurrentReferenceHashMap <K , V > extends AbstractMap <K , V > implements
60
- ConcurrentMap <K , V > {
59
+ public class ConcurrentReferenceHashMap <K , V > extends AbstractMap <K , V > implements ConcurrentMap <K , V > {
61
60
62
61
private static final int DEFAULT_INITIAL_CAPACITY = 16 ;
63
62
@@ -82,6 +81,9 @@ public class ConcurrentReferenceHashMap<K, V> extends AbstractMap<K, V> implemen
82
81
*/
83
82
private final float loadFactor ;
84
83
84
+ /**
85
+ * The reference type: SOFT or WEAK.
86
+ */
85
87
private final ReferenceType referenceType ;
86
88
87
89
/**
@@ -99,17 +101,15 @@ public class ConcurrentReferenceHashMap<K, V> extends AbstractMap<K, V> implemen
99
101
* Create a new {@code ConcurrentReferenceHashMap} instance.
100
102
*/
101
103
public ConcurrentReferenceHashMap () {
102
- this (DEFAULT_INITIAL_CAPACITY , DEFAULT_LOAD_FACTOR , DEFAULT_CONCURRENCY_LEVEL ,
103
- DEFAULT_REFERENCE_TYPE );
104
+ this (DEFAULT_INITIAL_CAPACITY , DEFAULT_LOAD_FACTOR , DEFAULT_CONCURRENCY_LEVEL , DEFAULT_REFERENCE_TYPE );
104
105
}
105
106
106
107
/**
107
108
* Create a new {@code ConcurrentReferenceHashMap} instance.
108
109
* @param initialCapacity the initial capacity of the map
109
110
*/
110
111
public ConcurrentReferenceHashMap (int initialCapacity ) {
111
- this (initialCapacity , DEFAULT_LOAD_FACTOR , DEFAULT_CONCURRENCY_LEVEL ,
112
- DEFAULT_REFERENCE_TYPE );
112
+ this (initialCapacity , DEFAULT_LOAD_FACTOR , DEFAULT_CONCURRENCY_LEVEL , DEFAULT_REFERENCE_TYPE );
113
113
}
114
114
115
115
/**
@@ -119,45 +119,44 @@ public ConcurrentReferenceHashMap(int initialCapacity) {
119
119
* exceeds this value resize will be attempted
120
120
*/
121
121
public ConcurrentReferenceHashMap (int initialCapacity , float loadFactor ) {
122
- this (initialCapacity , loadFactor , DEFAULT_CONCURRENCY_LEVEL ,
123
- DEFAULT_REFERENCE_TYPE );
122
+ this (initialCapacity , loadFactor , DEFAULT_CONCURRENCY_LEVEL , DEFAULT_REFERENCE_TYPE );
124
123
}
125
124
126
125
/**
127
126
* Create a new {@code ConcurrentReferenceHashMap} instance.
128
127
* @param initialCapacity the initial capacity of the map
129
- * @param concurrencyLevel the expected number of threads that will concurrently write
130
- * to the map
128
+ * @param concurrencyLevel the expected number of threads that will concurrently
129
+ * write to the map
131
130
*/
132
131
public ConcurrentReferenceHashMap (int initialCapacity , int concurrencyLevel ) {
133
- this (initialCapacity , DEFAULT_LOAD_FACTOR , concurrencyLevel ,
134
- DEFAULT_REFERENCE_TYPE );
132
+ this (initialCapacity , DEFAULT_LOAD_FACTOR , concurrencyLevel , DEFAULT_REFERENCE_TYPE );
135
133
}
136
134
137
135
/**
138
136
* Create a new {@code ConcurrentReferenceHashMap} instance.
139
137
* @param initialCapacity the initial capacity of the map
140
- * @param loadFactor the load factor. When the average number of references per table
141
- * exceeds this value resize will be attempted
142
- * @param concurrencyLevel the expected number of threads that will concurrently write
143
- * to the map
138
+ * @param loadFactor the load factor. When the average number of references per
139
+ * table exceeds this value, resize will be attempted.
140
+ * @param concurrencyLevel the expected number of threads that will concurrently
141
+ * write to the map
144
142
*/
145
- public ConcurrentReferenceHashMap (int initialCapacity , float loadFactor ,
146
- int concurrencyLevel ) {
143
+ public ConcurrentReferenceHashMap (int initialCapacity , float loadFactor , int concurrencyLevel ) {
147
144
this (initialCapacity , loadFactor , concurrencyLevel , DEFAULT_REFERENCE_TYPE );
148
145
}
149
146
150
147
/**
151
148
* Create a new {@code ConcurrentReferenceHashMap} instance.
152
149
* @param initialCapacity the initial capacity of the map
153
- * @param loadFactor the load factor. When the average number of references per table
154
- * exceeds this value resize will be attempted
155
- * @param concurrencyLevel the expected number of threads that will concurrently write
156
- * to the map
150
+ * @param loadFactor the load factor. When the average number of references per
151
+ * table exceeds this value, resize will be attempted.
152
+ * @param concurrencyLevel the expected number of threads that will concurrently
153
+ * write to the map
157
154
* @param referenceType the reference type used for entries
158
155
*/
159
- public ConcurrentReferenceHashMap (int initialCapacity , float loadFactor ,
160
- int concurrencyLevel , ReferenceType referenceType ) {
156
+ @ SuppressWarnings ("unchecked" )
157
+ public ConcurrentReferenceHashMap (int initialCapacity , float loadFactor , int concurrencyLevel ,
158
+ ReferenceType referenceType ) {
159
+
161
160
Assert .isTrue (concurrencyLevel > 0 , "ConcurrencyLevel must be positive" );
162
161
Assert .isTrue (initialCapacity >= 0 , "InitialCapacity must not be negative" );
163
162
Assert .isTrue (loadFactor > 0f , "LoadFactor must be positive" );
@@ -167,17 +166,12 @@ public ConcurrentReferenceHashMap(int initialCapacity, float loadFactor,
167
166
int size = 1 << this .shift ;
168
167
this .referenceType = referenceType ;
169
168
int roundedUpSegmentCapactity = (int ) ((initialCapacity + size - 1L ) / size );
170
- this .segments = createSegmentsArray ( size );
169
+ this .segments = ( Segment []) Array . newInstance ( Segment . class , size );
171
170
for (int i = 0 ; i < this .segments .length ; i ++) {
172
171
this .segments [i ] = new Segment (roundedUpSegmentCapactity );
173
172
}
174
173
}
175
174
176
- @ SuppressWarnings ("unchecked" )
177
- private Segment [] createSegmentsArray (int size ) {
178
- return (Segment []) Array .newInstance (Segment .class , size );
179
- }
180
-
181
175
182
176
protected final float getLoadFactor () {
183
177
return this .loadFactor ;
@@ -222,7 +216,7 @@ protected int getHash(Object o) {
222
216
public V get (Object key ) {
223
217
Reference <K , V > reference = getReference (key , Restructure .WHEN_NECESSARY );
224
218
Entry <K , V > entry = (reference == null ? null : reference .get ());
225
- return (entry == null ? null : entry .getValue ());
219
+ return (entry != null ? entry .getValue () : null );
226
220
}
227
221
228
222
@ Override
@@ -388,7 +382,7 @@ public static enum ReferenceType {
388
382
/**
389
383
* Use {@link WeakReference}s.
390
384
*/
391
- WEAK ;
385
+ WEAK
392
386
}
393
387
394
388
@@ -421,14 +415,12 @@ protected final class Segment extends ReentrantLock {
421
415
*/
422
416
private int resizeThreshold ;
423
417
424
-
425
418
public Segment (int initialCapacity ) {
426
419
this .referenceManager = createReferenceManager ();
427
420
this .initialSize = 1 << calculateShift (initialCapacity , MAXIMUM_SEGMENT_SIZE );
428
421
setReferences (createReferenceArray (this .initialSize ));
429
422
}
430
423
431
-
432
424
public Reference <K , V > getReference (Object key , int hash , Restructure restructure ) {
433
425
if (restructure == Restructure .WHEN_NECESSARY ) {
434
426
restructureIfNecessary (false );
@@ -452,17 +444,13 @@ public Reference<K, V> getReference(Object key, int hash, Restructure restructur
452
444
* @return the result of the operation
453
445
*/
454
446
public <T > T doTask (final int hash , final Object key , final Task <T > task ) {
455
-
456
447
boolean resize = task .hasOption (TaskOption .RESIZE );
457
-
458
448
if (task .hasOption (TaskOption .RESTRUCTURE_BEFORE )) {
459
449
restructureIfNecessary (resize );
460
450
}
461
-
462
451
if (task .hasOption (TaskOption .SKIP_IF_EMPTY ) && (this .count == 0 )) {
463
452
return task .execute (null , null , null );
464
453
}
465
-
466
454
lock ();
467
455
try {
468
456
final int index = getIndex (hash , this .references );
@@ -480,7 +468,8 @@ public void add(V value) {
480
468
}
481
469
};
482
470
return task .execute (reference , entry , entries );
483
- } finally {
471
+ }
472
+ finally {
484
473
unlock ();
485
474
if (task .hasOption (TaskOption .RESTRUCTURE_AFTER )) {
486
475
restructureIfNecessary (resize );
@@ -569,8 +558,7 @@ private void restructureIfNecessary(boolean allowResize) {
569
558
}
570
559
}
571
560
572
- private Reference <K , V > findInChain (Reference <K , V > reference , Object key ,
573
- int hash ) {
561
+ private Reference <K , V > findInChain (Reference <K , V > reference , Object key , int hash ) {
574
562
while (reference != null ) {
575
563
if (reference .getHash () == hash ) {
576
564
Entry <K , V > entry = reference .get ();
@@ -752,6 +740,7 @@ protected T execute(Reference<K, V> reference, Entry<K, V> entry) {
752
740
* Various options supported by a {@link Task}.
753
741
*/
754
742
private static enum TaskOption {
743
+
755
744
RESTRUCTURE_BEFORE , RESTRUCTURE_AFTER , SKIP_IF_EMPTY , RESIZE
756
745
}
757
746
@@ -783,8 +772,7 @@ public Iterator<Map.Entry<K, V>> iterator() {
783
772
public boolean contains (Object o ) {
784
773
if (o != null && o instanceof Map .Entry <?, ?>) {
785
774
Map .Entry <?, ?> entry = (java .util .Map .Entry <?, ?>) o ;
786
- Reference <K , V > reference = ConcurrentReferenceHashMap .this .getReference (
787
- entry .getKey (), Restructure .NEVER );
775
+ Reference <K , V > reference = ConcurrentReferenceHashMap .this .getReference (entry .getKey (), Restructure .NEVER );
788
776
Entry <K , V > other = (reference == null ? null : reference .get ());
789
777
if (other != null ) {
790
778
return ObjectUtils .nullSafeEquals (entry .getValue (), other .getValue ());
@@ -797,8 +785,7 @@ public boolean contains(Object o) {
797
785
public boolean remove (Object o ) {
798
786
if (o instanceof Map .Entry <?, ?>) {
799
787
Map .Entry <?, ?> entry = (Map .Entry <?, ?>) o ;
800
- return ConcurrentReferenceHashMap .this .remove (entry .getKey (),
801
- entry .getValue ());
788
+ return ConcurrentReferenceHashMap .this .remove (entry .getKey (), entry .getValue ());
802
789
}
803
790
return false ;
804
791
}
@@ -897,6 +884,7 @@ public void remove() {
897
884
* The types of restructuring that can be performed.
898
885
*/
899
886
protected static enum Restructure {
887
+
900
888
WHEN_NECESSARY , NEVER
901
889
}
902
890
@@ -916,8 +904,7 @@ protected class ReferenceManager {
916
904
* @param next the next reference in the chain or {@code null}
917
905
* @return a new {@link Reference}
918
906
*/
919
- public Reference <K , V > createReference (Entry <K , V > entry , int hash ,
920
- Reference <K , V > next ) {
907
+ public Reference <K , V > createReference (Entry <K , V > entry , int hash , Reference <K , V > next ) {
921
908
if (ConcurrentReferenceHashMap .this .referenceType == ReferenceType .WEAK ) {
922
909
return new WeakEntryReference <K , V >(entry , hash , next , this .queue );
923
910
}
@@ -941,15 +928,13 @@ public Reference<K, V> pollForPurge() {
941
928
/**
942
929
* Internal {@link Reference} implementation for {@link SoftReference}s.
943
930
*/
944
- private static final class SoftEntryReference <K , V > extends
945
- SoftReference <Entry <K , V >> implements Reference <K , V > {
931
+ private static final class SoftEntryReference <K , V > extends SoftReference <Entry <K , V >> implements Reference <K , V > {
946
932
947
933
private final int hash ;
948
934
949
935
private final Reference <K , V > nextReference ;
950
936
951
- public SoftEntryReference (Entry <K , V > entry , int hash , Reference <K , V > next ,
952
- ReferenceQueue <Entry <K , V >> queue ) {
937
+ public SoftEntryReference (Entry <K , V > entry , int hash , Reference <K , V > next , ReferenceQueue <Entry <K , V >> queue ) {
953
938
super (entry , queue );
954
939
this .hash = hash ;
955
940
this .nextReference = next ;
@@ -973,15 +958,13 @@ public void release() {
973
958
/**
974
959
* Internal {@link Reference} implementation for {@link WeakReference}s.
975
960
*/
976
- private static final class WeakEntryReference <K , V > extends
977
- WeakReference <Entry <K , V >> implements Reference <K , V > {
961
+ private static final class WeakEntryReference <K , V > extends WeakReference <Entry <K , V >> implements Reference <K , V > {
978
962
979
963
private final int hash ;
980
964
981
965
private final Reference <K , V > nextReference ;
982
966
983
- public WeakEntryReference (Entry <K , V > entry , int hash , Reference <K , V > next ,
984
- ReferenceQueue <Entry <K , V >> queue ) {
967
+ public WeakEntryReference (Entry <K , V > entry , int hash , Reference <K , V > next , ReferenceQueue <Entry <K , V >> queue ) {
985
968
super (entry , queue );
986
969
this .hash = hash ;
987
970
this .nextReference = next ;
@@ -1000,4 +983,5 @@ public void release() {
1000
983
clear ();
1001
984
}
1002
985
}
986
+
1003
987
}
0 commit comments