62 |
|
* does <em>not</em> allow <tt>null</tt> to be used as a key or value. |
63 |
|
* |
64 |
|
* <p>This class is a member of the |
65 |
< |
* <a href="{@docRoot}/../guide/collections/index.html"> |
65 |
> |
* <a href="{@docRoot}/../technotes/guides/collections/index.html"> |
66 |
|
* Java Collections Framework</a>. |
67 |
|
* |
68 |
|
* @since 1.5 |
146 |
|
/* ---------------- Small Utilities -------------- */ |
147 |
|
|
148 |
|
/** |
149 |
< |
* Returns a hash code for non-null Object x. |
150 |
< |
* Uses the same hash code spreader as most other java.util hash tables. |
151 |
< |
* @param x the object serving as a key |
152 |
< |
* @return the hash code |
153 |
< |
*/ |
154 |
< |
static int hash(Object x) { |
155 |
< |
int h = x.hashCode(); |
156 |
< |
h += ~(h << 9); |
157 |
< |
h ^= (h >>> 14); |
158 |
< |
h += (h << 4); |
159 |
< |
h ^= (h >>> 10); |
149 |
> |
* Applies a supplemental hash function to a given hashCode, which |
150 |
> |
* defends against poor quality hash functions. This is critical |
151 |
> |
* because ConcurrentHashMap uses power-of-two length hash tables, |
152 |
> |
* that otherwise encounter collisions for hashCodes that do not |
153 |
> |
* differ in lower bits. |
154 |
> |
*/ |
155 |
> |
private static int hash(int h) { |
156 |
> |
// Spread bits to regularize both segment and index locations, |
157 |
> |
// using variant of Jenkins's shift-based hash. |
158 |
> |
h += ~(h << 13); |
159 |
> |
h ^= h >>> 7; |
160 |
> |
h += h << 3; |
161 |
> |
h ^= h >>> 17; |
162 |
> |
h += h << 5; |
163 |
|
return h; |
164 |
|
} |
165 |
|
|
753 |
|
} |
754 |
|
|
755 |
|
/** |
756 |
< |
* Returns the value to which this map maps the specified key, or |
757 |
< |
* <tt>null</tt> if the map contains no mapping for the key. |
756 |
> |
* Returns the value to which the specified key is mapped, |
757 |
> |
* or {@code null} if this map contains no mapping for the key. |
758 |
> |
* |
759 |
> |
* <p>More formally, if this map contains a mapping from a key |
760 |
> |
* {@code k} to a value {@code v} such that {@code key.equals(k)}, |
761 |
> |
* then this method returns {@code v}; otherwise it returns |
762 |
> |
* {@code null}. (There can be at most one such mapping.) |
763 |
|
* |
756 |
– |
* @param key key whose associated value is to be returned |
757 |
– |
* @return the value to which this map maps the specified key, or |
758 |
– |
* <tt>null</tt> if the map contains no mapping for the key |
764 |
|
* @throws NullPointerException if the specified key is null |
765 |
|
*/ |
766 |
|
public V get(Object key) { |
767 |
< |
int hash = hash(key); // throws NullPointerException if key null |
767 |
> |
int hash = hash(key.hashCode()); |
768 |
|
return segmentFor(hash).get(key, hash); |
769 |
|
} |
770 |
|
|
778 |
|
* @throws NullPointerException if the specified key is null |
779 |
|
*/ |
780 |
|
public boolean containsKey(Object key) { |
781 |
< |
int hash = hash(key); // throws NullPointerException if key null |
781 |
> |
int hash = hash(key.hashCode()); |
782 |
|
return segmentFor(hash).containsKey(key, hash); |
783 |
|
} |
784 |
|
|
878 |
|
public V put(K key, V value) { |
879 |
|
if (value == null) |
880 |
|
throw new NullPointerException(); |
881 |
< |
int hash = hash(key); |
881 |
> |
int hash = hash(key.hashCode()); |
882 |
|
return segmentFor(hash).put(key, hash, value, false); |
883 |
|
} |
884 |
|
|
892 |
|
public V putIfAbsent(K key, V value) { |
893 |
|
if (value == null) |
894 |
|
throw new NullPointerException(); |
895 |
< |
int hash = hash(key); |
895 |
> |
int hash = hash(key.hashCode()); |
896 |
|
return segmentFor(hash).put(key, hash, value, true); |
897 |
|
} |
898 |
|
|
904 |
|
* @param m mappings to be stored in this map |
905 |
|
*/ |
906 |
|
public void putAll(Map<? extends K, ? extends V> m) { |
907 |
< |
for (Iterator<? extends Map.Entry<? extends K, ? extends V>> it = (Iterator<? extends Map.Entry<? extends K, ? extends V>>) m.entrySet().iterator(); it.hasNext(); ) { |
903 |
< |
Entry<? extends K, ? extends V> e = it.next(); |
907 |
> |
for (Map.Entry<? extends K, ? extends V> e : m.entrySet()) |
908 |
|
put(e.getKey(), e.getValue()); |
905 |
– |
} |
909 |
|
} |
910 |
|
|
911 |
|
/** |
914 |
|
* |
915 |
|
* @param key the key that needs to be removed |
916 |
|
* @return the previous value associated with <tt>key</tt>, or |
917 |
< |
* <tt>null</tt> if there was no mapping for <tt>key</tt>. |
917 |
> |
* <tt>null</tt> if there was no mapping for <tt>key</tt> |
918 |
|
* @throws NullPointerException if the specified key is null |
919 |
|
*/ |
920 |
|
public V remove(Object key) { |
921 |
< |
int hash = hash(key); |
921 |
> |
int hash = hash(key.hashCode()); |
922 |
|
return segmentFor(hash).remove(key, hash, null); |
923 |
|
} |
924 |
|
|
928 |
|
* @throws NullPointerException if the specified key is null |
929 |
|
*/ |
930 |
|
public boolean remove(Object key, Object value) { |
931 |
+ |
int hash = hash(key.hashCode()); |
932 |
|
if (value == null) |
933 |
|
return false; |
930 |
– |
int hash = hash(key); |
934 |
|
return segmentFor(hash).remove(key, hash, value) != null; |
935 |
|
} |
936 |
|
|
942 |
|
public boolean replace(K key, V oldValue, V newValue) { |
943 |
|
if (oldValue == null || newValue == null) |
944 |
|
throw new NullPointerException(); |
945 |
< |
int hash = hash(key); |
945 |
> |
int hash = hash(key.hashCode()); |
946 |
|
return segmentFor(hash).replace(key, hash, oldValue, newValue); |
947 |
|
} |
948 |
|
|
956 |
|
public V replace(K key, V value) { |
957 |
|
if (value == null) |
958 |
|
throw new NullPointerException(); |
959 |
< |
int hash = hash(key); |
959 |
> |
int hash = hash(key.hashCode()); |
960 |
|
return segmentFor(hash).replace(key, hash, value); |
961 |
|
} |
962 |
|
|
1129 |
|
* Custom Entry class used by EntryIterator.next(), that relays |
1130 |
|
* setValue changes to the underlying map. |
1131 |
|
*/ |
1132 |
< |
static final class WriteThroughEntry<K,V> |
1132 |
> |
final class WriteThroughEntry |
1133 |
|
extends AbstractMap.SimpleEntry<K,V> |
1134 |
|
{ |
1135 |
< |
private final ConcurrentHashMap<K,V> map; |
1133 |
< |
WriteThroughEntry(ConcurrentHashMap map, K k, V v) { |
1135 |
> |
WriteThroughEntry(K k, V v) { |
1136 |
|
super(k,v); |
1135 |
– |
this.map = map; |
1137 |
|
} |
1138 |
|
|
1139 |
|
/** |
1148 |
|
public V setValue(V value) { |
1149 |
|
if (value == null) throw new NullPointerException(); |
1150 |
|
V v = super.setValue(value); |
1151 |
< |
map.put(getKey(), value); |
1151 |
> |
ConcurrentHashMap.this.put(getKey(), value); |
1152 |
|
return v; |
1153 |
|
} |
1154 |
|
} |
1159 |
|
{ |
1160 |
|
public Map.Entry<K,V> next() { |
1161 |
|
HashEntry<K,V> e = super.nextEntry(); |
1162 |
< |
return new WriteThroughEntry<K,V>(ConcurrentHashMap.this, |
1162 |
< |
e.key, e.value); |
1162 |
> |
return new WriteThroughEntry(e.key, e.value); |
1163 |
|
} |
1164 |
|
} |
1165 |
|
|
1179 |
|
public void clear() { |
1180 |
|
ConcurrentHashMap.this.clear(); |
1181 |
|
} |
1182 |
– |
public Object[] toArray() { |
1183 |
– |
Collection<K> c = new ArrayList<K>(size()); |
1184 |
– |
for (K k : this) |
1185 |
– |
c.add(k); |
1186 |
– |
return c.toArray(); |
1187 |
– |
} |
1188 |
– |
public <T> T[] toArray(T[] a) { |
1189 |
– |
Collection<K> c = new ArrayList<K>(); |
1190 |
– |
for (K k : this) |
1191 |
– |
c.add(k); |
1192 |
– |
return c.toArray(a); |
1193 |
– |
} |
1182 |
|
} |
1183 |
|
|
1184 |
|
final class Values extends AbstractCollection<V> { |
1194 |
|
public void clear() { |
1195 |
|
ConcurrentHashMap.this.clear(); |
1196 |
|
} |
1209 |
– |
public Object[] toArray() { |
1210 |
– |
Collection<V> c = new ArrayList<V>(size()); |
1211 |
– |
for (V v : this) |
1212 |
– |
c.add(v); |
1213 |
– |
return c.toArray(); |
1214 |
– |
} |
1215 |
– |
public <T> T[] toArray(T[] a) { |
1216 |
– |
Collection<V> c = new ArrayList<V>(size()); |
1217 |
– |
for (V v : this) |
1218 |
– |
c.add(v); |
1219 |
– |
return c.toArray(a); |
1220 |
– |
} |
1197 |
|
} |
1198 |
|
|
1199 |
|
final class EntrySet extends AbstractSet<Map.Entry<K,V>> { |
1219 |
|
public void clear() { |
1220 |
|
ConcurrentHashMap.this.clear(); |
1221 |
|
} |
1246 |
– |
public Object[] toArray() { |
1247 |
– |
Collection<Map.Entry<K,V>> c = new ArrayList<Map.Entry<K,V>>(size()); |
1248 |
– |
for (Map.Entry<K,V> e : this) |
1249 |
– |
c.add(e); |
1250 |
– |
return c.toArray(); |
1251 |
– |
} |
1252 |
– |
public <T> T[] toArray(T[] a) { |
1253 |
– |
Collection<Map.Entry<K,V>> c = new ArrayList<Map.Entry<K,V>>(size()); |
1254 |
– |
for (Map.Entry<K,V> e : this) |
1255 |
– |
c.add(e); |
1256 |
– |
return c.toArray(a); |
1257 |
– |
} |
1258 |
– |
|
1222 |
|
} |
1223 |
|
|
1224 |
|
/* ---------------- Serialization Support -------------- */ |