199 |
|
static { |
200 |
|
try { |
201 |
|
UNSAFE = sun.misc.Unsafe.getUnsafe(); |
202 |
< |
Class k = HashEntry.class; |
202 |
> |
Class<?> k = HashEntry.class; |
203 |
|
nextOffset = UNSAFE.objectFieldOffset |
204 |
|
(k.getDeclaredField("next")); |
205 |
|
} catch (Exception e) { |
404 |
|
int newCapacity = oldCapacity << 1; |
405 |
|
threshold = (int)(newCapacity * loadFactor); |
406 |
|
HashEntry<K,V>[] newTable = |
407 |
< |
(HashEntry<K,V>[]) new HashEntry[newCapacity]; |
407 |
> |
(HashEntry<K,V>[]) new HashEntry<?,?>[newCapacity]; |
408 |
|
int sizeMask = newCapacity - 1; |
409 |
|
for (int i = 0; i < oldCapacity ; i++) { |
410 |
|
HashEntry<K,V> e = oldTable[i]; |
648 |
|
int cap = proto.table.length; |
649 |
|
float lf = proto.loadFactor; |
650 |
|
int threshold = (int)(cap * lf); |
651 |
< |
HashEntry<K,V>[] tab = (HashEntry<K,V>[])new HashEntry[cap]; |
651 |
> |
HashEntry<K,V>[] tab = (HashEntry<K,V>[])new HashEntry<?,?>[cap]; |
652 |
|
if ((seg = (Segment<K,V>)UNSAFE.getObjectVolatile(ss, u)) |
653 |
|
== null) { // recheck |
654 |
|
Segment<K,V> s = new Segment<K,V>(lf, threshold, tab); |
729 |
|
// create segments and segments[0] |
730 |
|
Segment<K,V> s0 = |
731 |
|
new Segment<K,V>(loadFactor, (int)(cap * loadFactor), |
732 |
< |
(HashEntry<K,V>[])new HashEntry[cap]); |
733 |
< |
Segment<K,V>[] ss = (Segment<K,V>[])new Segment[ssize]; |
732 |
> |
(HashEntry<K,V>[])new HashEntry<?,?>[cap]); |
733 |
> |
Segment<K,V>[] ss = (Segment<K,V>[])new Segment<?,?>[ssize]; |
734 |
|
UNSAFE.putOrderedObject(ss, SBASE, s0); // ordered write of segments[0] |
735 |
|
this.segments = ss; |
736 |
|
} |
840 |
|
// Try a few times to get accurate count. On failure due to |
841 |
|
// continuous async changes in table, resort to locking. |
842 |
|
final Segment<K,V>[] segments = this.segments; |
843 |
< |
int size; |
844 |
< |
boolean overflow; // true if size overflows 32 bits |
845 |
< |
long sum; // sum of modCounts |
846 |
< |
long last = 0L; // previous sum |
847 |
< |
int retries = -1; // first iteration isn't retry |
848 |
< |
try { |
849 |
< |
for (;;) { |
850 |
< |
if (retries++ == RETRIES_BEFORE_LOCK) { |
851 |
< |
for (int j = 0; j < segments.length; ++j) |
852 |
< |
ensureSegment(j).lock(); // force creation |
853 |
< |
} |
854 |
< |
sum = 0L; |
855 |
< |
size = 0; |
856 |
< |
overflow = false; |
857 |
< |
for (int j = 0; j < segments.length; ++j) { |
858 |
< |
Segment<K,V> seg = segmentAt(segments, j); |
859 |
< |
if (seg != null) { |
860 |
< |
sum += seg.modCount; |
861 |
< |
int c = seg.count; |
862 |
< |
if (c < 0 || (size += c) < 0) |
863 |
< |
overflow = true; |
864 |
< |
} |
843 |
> |
final int segmentCount = segments.length; |
844 |
> |
|
845 |
> |
long previousSum = 0L; |
846 |
> |
for (int retries = -1; retries < RETRIES_BEFORE_LOCK; retries++) { |
847 |
> |
long sum = 0L; // sum of modCounts |
848 |
> |
long size = 0L; |
849 |
> |
for (int i = 0; i < segmentCount; i++) { |
850 |
> |
Segment<K,V> segment = segmentAt(segments, i); |
851 |
> |
if (segment != null) { |
852 |
> |
sum += segment.modCount; |
853 |
> |
size += segment.count; |
854 |
|
} |
866 |
– |
if (sum == last) |
867 |
– |
break; |
868 |
– |
last = sum; |
869 |
– |
} |
870 |
– |
} finally { |
871 |
– |
if (retries > RETRIES_BEFORE_LOCK) { |
872 |
– |
for (int j = 0; j < segments.length; ++j) |
873 |
– |
segmentAt(segments, j).unlock(); |
855 |
|
} |
856 |
+ |
if (sum == previousSum) |
857 |
+ |
return ((size >>> 31) == 0) ? (int) size : Integer.MAX_VALUE; |
858 |
+ |
previousSum = sum; |
859 |
|
} |
860 |
< |
return overflow ? Integer.MAX_VALUE : size; |
860 |
> |
|
861 |
> |
long size = 0L; |
862 |
> |
for (int i = 0; i < segmentCount; i++) { |
863 |
> |
Segment<K,V> segment = ensureSegment(i); |
864 |
> |
segment.lock(); |
865 |
> |
size += segment.count; |
866 |
> |
} |
867 |
> |
for (int i = 0; i < segmentCount; i++) |
868 |
> |
segments[i].unlock(); |
869 |
> |
return ((size >>> 31) == 0) ? (int) size : Integer.MAX_VALUE; |
870 |
|
} |
871 |
|
|
872 |
|
/** |
942 |
|
if (value == null) |
943 |
|
throw new NullPointerException(); |
944 |
|
final Segment<K,V>[] segments = this.segments; |
945 |
< |
boolean found = false; |
946 |
< |
long last = 0L; // previous sum |
954 |
< |
int retries = -1; |
945 |
> |
long previousSum = 0L; |
946 |
> |
int lockCount = 0; |
947 |
|
try { |
948 |
< |
outer: for (;;) { |
949 |
< |
if (retries++ == RETRIES_BEFORE_LOCK) { |
950 |
< |
for (int j = 0; j < segments.length; ++j) |
951 |
< |
ensureSegment(j).lock(); // force creation |
952 |
< |
} |
953 |
< |
long sum = 0L; |
954 |
< |
for (int j = 0; j < segments.length; ++j) { |
955 |
< |
HashEntry<K,V>[] tab; |
956 |
< |
Segment<K,V> seg = segmentAt(segments, j); |
957 |
< |
if (seg != null && (tab = seg.table) != null) { |
948 |
> |
for (int retries = -1; ; retries++) { |
949 |
> |
long sum = 0L; // sum of modCounts |
950 |
> |
for (int j = 0; j < segments.length; j++) { |
951 |
> |
Segment<K,V> segment; |
952 |
> |
if (retries == RETRIES_BEFORE_LOCK) { |
953 |
> |
segment = ensureSegment(j); |
954 |
> |
segment.lock(); |
955 |
> |
lockCount++; |
956 |
> |
} else { |
957 |
> |
segment = segmentAt(segments, j); |
958 |
> |
if (segment == null) |
959 |
> |
continue; |
960 |
> |
} |
961 |
> |
HashEntry<K,V>[] tab = segment.table; |
962 |
> |
if (tab != null) { |
963 |
|
for (int i = 0 ; i < tab.length; i++) { |
964 |
|
HashEntry<K,V> e; |
965 |
|
for (e = entryAt(tab, i); e != null; e = e.next) { |
966 |
|
V v = e.value; |
967 |
< |
if (v != null && value.equals(v)) { |
968 |
< |
found = true; |
972 |
< |
break outer; |
973 |
< |
} |
967 |
> |
if (v != null && value.equals(v)) |
968 |
> |
return true; |
969 |
|
} |
970 |
|
} |
971 |
< |
sum += seg.modCount; |
971 |
> |
sum += segment.modCount; |
972 |
|
} |
973 |
|
} |
974 |
< |
if (retries > 0 && sum == last) |
975 |
< |
break; |
976 |
< |
last = sum; |
974 |
> |
if ((retries >= 0 && sum == previousSum) || lockCount > 0) |
975 |
> |
return false; |
976 |
> |
previousSum = sum; |
977 |
|
} |
978 |
|
} finally { |
979 |
< |
if (retries > RETRIES_BEFORE_LOCK) { |
980 |
< |
for (int j = 0; j < segments.length; ++j) |
986 |
< |
segmentAt(segments, j).unlock(); |
987 |
< |
} |
979 |
> |
for (int j = 0; j < lockCount; j++) |
980 |
> |
segments[j].unlock(); |
981 |
|
} |
989 |
– |
return found; |
982 |
|
} |
983 |
|
|
984 |
|
/** |
988 |
|
* full compatibility with class {@link java.util.Hashtable}, |
989 |
|
* which supported this method prior to introduction of the |
990 |
|
* Java Collections framework. |
991 |
< |
|
991 |
> |
* |
992 |
|
* @param value a value to search for |
993 |
|
* @return <tt>true</tt> if and only if some key maps to the |
994 |
|
* <tt>value</tt> argument in this table as |
1441 |
|
Segment<K,V> seg = segments[k]; |
1442 |
|
if (seg != null) { |
1443 |
|
seg.threshold = (int)(cap * seg.loadFactor); |
1444 |
< |
seg.table = (HashEntry<K,V>[]) new HashEntry[cap]; |
1444 |
> |
seg.table = (HashEntry<K,V>[]) new HashEntry<?,?>[cap]; |
1445 |
|
} |
1446 |
|
} |
1447 |
|
|
1466 |
|
int ss, ts; |
1467 |
|
try { |
1468 |
|
UNSAFE = sun.misc.Unsafe.getUnsafe(); |
1469 |
< |
Class tc = HashEntry[].class; |
1470 |
< |
Class sc = Segment[].class; |
1469 |
> |
Class<?> tc = HashEntry[].class; |
1470 |
> |
Class<?> sc = Segment[].class; |
1471 |
|
TBASE = UNSAFE.arrayBaseOffset(tc); |
1472 |
|
SBASE = UNSAFE.arrayBaseOffset(sc); |
1473 |
|
ts = UNSAFE.arrayIndexScale(tc); |