210 |
|
|
211 |
|
/** |
212 |
|
* Gets the ith element of given table (if nonnull) with volatile |
213 |
< |
* read semantics. |
213 |
> |
* read semantics. Note: This is manually integrated into a few |
214 |
> |
* performance-sensitive methods to reduce call overhead. |
215 |
|
*/ |
216 |
|
@SuppressWarnings("unchecked") |
217 |
|
static final <K,V> HashEntry<K,V> entryAt(HashEntry<K,V>[] tab, int i) { |
361 |
|
else |
362 |
|
node = new HashEntry<K,V>(hash, key, value, first); |
363 |
|
int c = count + 1; |
364 |
< |
if (c > threshold && first != null && |
364 |
< |
tab.length < MAXIMUM_CAPACITY) |
364 |
> |
if (c > threshold && tab.length < MAXIMUM_CAPACITY) |
365 |
|
rehash(node); |
366 |
|
else |
367 |
|
setEntryAt(tab, index, node); |
618 |
|
|
619 |
|
/** |
620 |
|
* Gets the jth element of given segment array (if nonnull) with |
621 |
< |
* volatile element access semantics via Unsafe. |
621 |
> |
* volatile element access semantics via Unsafe. (The null check |
622 |
> |
* can trigger harmlessly only during deserialization.) Note: |
623 |
> |
* because each element of segments array is set only once (using |
624 |
> |
* fully ordered writes), some performance-sensitive methods rely |
625 |
> |
* on this method only as a recheck upon null reads. |
626 |
|
*/ |
627 |
|
@SuppressWarnings("unchecked") |
628 |
|
static final <K,V> Segment<K,V> segmentAt(Segment<K,V>[] ss, int j) { |
888 |
|
* @throws NullPointerException if the specified key is null |
889 |
|
*/ |
890 |
|
public V get(Object key) { |
891 |
< |
int hash = hash(key.hashCode()); |
892 |
< |
for (HashEntry<K,V> e = entryForHash(segmentForHash(hash), hash); |
893 |
< |
e != null; e = e.next) { |
894 |
< |
K k; |
895 |
< |
if ((k = e.key) == key || (e.hash == hash && key.equals(k))) |
896 |
< |
return e.value; |
891 |
> |
Segment<K,V> s; // manually integrate access methods to reduce overhead |
892 |
> |
HashEntry<K,V>[] tab; |
893 |
> |
int h = hash(key.hashCode()); |
894 |
> |
long u = (((h >>> segmentShift) & segmentMask) << SSHIFT) + SBASE; |
895 |
> |
if ((s = (Segment<K,V>)UNSAFE.getObjectVolatile(segments, u)) != null && |
896 |
> |
(tab = s.table) != null) { |
897 |
> |
for (HashEntry<K,V> e = (HashEntry<K,V>) UNSAFE.getObjectVolatile |
898 |
> |
(tab, ((long)(((tab.length - 1) & h)) << TSHIFT) + TBASE); |
899 |
> |
e != null; e = e.next) { |
900 |
> |
K k; |
901 |
> |
if ((k = e.key) == key || (e.hash == h && key.equals(k))) |
902 |
> |
return e.value; |
903 |
> |
} |
904 |
|
} |
905 |
|
return null; |
906 |
|
} |
914 |
|
* <tt>equals</tt> method; <tt>false</tt> otherwise. |
915 |
|
* @throws NullPointerException if the specified key is null |
916 |
|
*/ |
917 |
+ |
@SuppressWarnings("unchecked") |
918 |
|
public boolean containsKey(Object key) { |
919 |
< |
int hash = hash(key.hashCode()); |
920 |
< |
for (HashEntry<K,V> e = entryForHash(segmentForHash(hash), hash); |
921 |
< |
e != null; e = e.next) { |
922 |
< |
K k; |
923 |
< |
if ((k = e.key) == key || (e.hash == hash && key.equals(k))) |
924 |
< |
return true; |
919 |
> |
Segment<K,V> s; // same as get() except no need for volatile value read |
920 |
> |
HashEntry<K,V>[] tab; |
921 |
> |
int h = hash(key.hashCode()); |
922 |
> |
long u = (((h >>> segmentShift) & segmentMask) << SSHIFT) + SBASE; |
923 |
> |
if ((s = (Segment<K,V>)UNSAFE.getObjectVolatile(segments, u)) != null && |
924 |
> |
(tab = s.table) != null) { |
925 |
> |
for (HashEntry<K,V> e = (HashEntry<K,V>) UNSAFE.getObjectVolatile |
926 |
> |
(tab, ((long)(((tab.length - 1) & h)) << TSHIFT) + TBASE); |
927 |
> |
e != null; e = e.next) { |
928 |
> |
K k; |
929 |
> |
if ((k = e.key) == key || (e.hash == h && key.equals(k))) |
930 |
> |
return true; |
931 |
> |
} |
932 |
|
} |
933 |
|
return false; |
934 |
|
} |
1022 |
|
* <tt>null</tt> if there was no mapping for <tt>key</tt> |
1023 |
|
* @throws NullPointerException if the specified key or value is null |
1024 |
|
*/ |
1025 |
+ |
@SuppressWarnings("unchecked") |
1026 |
|
public V put(K key, V value) { |
1027 |
+ |
Segment<K,V> s; |
1028 |
|
if (value == null) |
1029 |
|
throw new NullPointerException(); |
1030 |
|
int hash = hash(key.hashCode()); |
1031 |
|
int j = (hash >>> segmentShift) & segmentMask; |
1032 |
< |
Segment<K,V> s = segmentAt(segments, j); |
1033 |
< |
if (s == null) |
1032 |
> |
if ((s = (Segment<K,V>)UNSAFE.getObject // nonvolatile; recheck |
1033 |
> |
(segments, (j << SSHIFT) + SBASE)) == null) // in ensureSegment |
1034 |
|
s = ensureSegment(j); |
1035 |
|
return s.put(key, hash, value, false); |
1036 |
|
} |
1042 |
|
* or <tt>null</tt> if there was no mapping for the key |
1043 |
|
* @throws NullPointerException if the specified key or value is null |
1044 |
|
*/ |
1045 |
+ |
@SuppressWarnings("unchecked") |
1046 |
|
public V putIfAbsent(K key, V value) { |
1047 |
+ |
Segment<K,V> s; |
1048 |
|
if (value == null) |
1049 |
|
throw new NullPointerException(); |
1050 |
|
int hash = hash(key.hashCode()); |
1051 |
|
int j = (hash >>> segmentShift) & segmentMask; |
1052 |
< |
Segment<K,V> s = segmentAt(segments, j); |
1053 |
< |
if (s == null) |
1052 |
> |
if ((s = (Segment<K,V>)UNSAFE.getObject |
1053 |
> |
(segments, (j << SSHIFT) + SBASE)) == null) |
1054 |
|
s = ensureSegment(j); |
1055 |
|
return s.put(key, hash, value, true); |
1056 |
|
} |