161 */
162 static final int MIN_SEGMENT_TABLE_CAPACITY = 2;
163
164 /**
165 * The maximum number of segments to allow; used to bound
166 * constructor arguments. Must be power of two less than 1 << 24.
167 */
168 static final int MAX_SEGMENTS = 1 << 16; // slightly conservative
169
170 /**
171 * Number of unsynchronized retries in size and containsValue
172 * methods before resorting to locking. This is used to avoid
173 * unbounded retries if tables undergo continuous modification
174 * which would make it impossible to obtain an accurate result.
175 */
176 static final int RETRIES_BEFORE_LOCK = 2;
177
178 /* ---------------- Fields -------------- */
179
180 /**
181 * Mask value for indexing into segments. The upper bits of a
182 * key's hash code are used to choose the segment.
183 */
184 final int segmentMask;
185
186 /**
187 * Shift value for indexing within segments.
188 */
189 final int segmentShift;
190
191 /**
192 * The segments, each of which is a specialized hash table.
193 */
194 final Segment<K,V>[] segments;
195
196 transient Set<K> keySet;
197 transient Set<Map.Entry<K,V>> entrySet;
198 transient Collection<V> values;
199
200 /**
248 (HashEntry<K,V>) UNSAFE.getObjectVolatile
249 (tab, ((long)i << TSHIFT) + TBASE);
250 }
251
252 /**
253 * Sets the ith element of given table, with volatile write
254 * semantics. (See above about use of putOrderedObject.)
255 */
256 static final <K,V> void setEntryAt(HashEntry<K,V>[] tab, int i,
257 HashEntry<K,V> e) {
258 UNSAFE.putOrderedObject(tab, ((long)i << TSHIFT) + TBASE, e);
259 }
260
261 /**
262 * Applies a supplemental hash function to a given hashCode, which
263 * defends against poor quality hash functions. This is critical
264 * because ConcurrentHashMap uses power-of-two length hash tables,
265 * that otherwise encounter collisions for hashCodes that do not
266 * differ in lower or upper bits.
267 */
268 private static int hash(int h) {
269 // Spread bits to regularize both segment and index locations,
270 // using variant of single-word Wang/Jenkins hash.
271 h += (h << 15) ^ 0xffffcd7d;
272 h ^= (h >>> 10);
273 h += (h << 3);
274 h ^= (h >>> 6);
275 h += (h << 2) + (h << 14);
276 return h ^ (h >>> 16);
277 }
278
279 /**
280 * Segments are specialized versions of hash tables. This
281 * subclasses from ReentrantLock opportunistically, just to
282 * simplify some locking and avoid separate construction.
283 */
284 static final class Segment<K,V> extends ReentrantLock implements Serializable {
285 /*
286 * Segments maintain a table of entry lists that are always
287 * kept in a consistent state, so can be read (via volatile
288 * reads of segments and tables) without locking. This
902 segmentAt(segments, j).unlock();
903 }
904 }
905 return overflow ? Integer.MAX_VALUE : size;
906 }
907
908 /**
909 * Returns the value to which the specified key is mapped,
910 * or {@code null} if this map contains no mapping for the key.
911 *
912 * <p>More formally, if this map contains a mapping from a key
913 * {@code k} to a value {@code v} such that {@code key.equals(k)},
914 * then this method returns {@code v}; otherwise it returns
915 * {@code null}. (There can be at most one such mapping.)
916 *
917 * @throws NullPointerException if the specified key is null
918 */
919 public V get(Object key) {
920 Segment<K,V> s; // manually integrate access methods to reduce overhead
921 HashEntry<K,V>[] tab;
922 int h = hash(key.hashCode());
923 long u = (((h >>> segmentShift) & segmentMask) << SSHIFT) + SBASE;
924 if ((s = (Segment<K,V>)UNSAFE.getObjectVolatile(segments, u)) != null &&
925 (tab = s.table) != null) {
926 for (HashEntry<K,V> e = (HashEntry<K,V>) UNSAFE.getObjectVolatile
927 (tab, ((long)(((tab.length - 1) & h)) << TSHIFT) + TBASE);
928 e != null; e = e.next) {
929 K k;
930 if ((k = e.key) == key || (e.hash == h && key.equals(k)))
931 return e.value;
932 }
933 }
934 return null;
935 }
936
937 /**
938 * Tests if the specified object is a key in this table.
939 *
940 * @param key possible key
941 * @return <tt>true</tt> if and only if the specified object
942 * is a key in this table, as determined by the
943 * <tt>equals</tt> method; <tt>false</tt> otherwise.
944 * @throws NullPointerException if the specified key is null
945 */
946 @SuppressWarnings("unchecked")
947 public boolean containsKey(Object key) {
948 Segment<K,V> s; // same as get() except no need for volatile value read
949 HashEntry<K,V>[] tab;
950 int h = hash(key.hashCode());
951 long u = (((h >>> segmentShift) & segmentMask) << SSHIFT) + SBASE;
952 if ((s = (Segment<K,V>)UNSAFE.getObjectVolatile(segments, u)) != null &&
953 (tab = s.table) != null) {
954 for (HashEntry<K,V> e = (HashEntry<K,V>) UNSAFE.getObjectVolatile
955 (tab, ((long)(((tab.length - 1) & h)) << TSHIFT) + TBASE);
956 e != null; e = e.next) {
957 K k;
958 if ((k = e.key) == key || (e.hash == h && key.equals(k)))
959 return true;
960 }
961 }
962 return false;
963 }
964
965 /**
966 * Returns <tt>true</tt> if this map maps one or more keys to the
967 * specified value. Note: This method requires a full internal
968 * traversal of the hash table, and so is much slower than
969 * method <tt>containsKey</tt>.
970 *
1039 }
1040
1041 /**
1042 * Maps the specified key to the specified value in this table.
1043 * Neither the key nor the value can be null.
1044 *
1045 * <p> The value can be retrieved by calling the <tt>get</tt> method
1046 * with a key that is equal to the original key.
1047 *
1048 * @param key key with which the specified value is to be associated
1049 * @param value value to be associated with the specified key
1050 * @return the previous value associated with <tt>key</tt>, or
1051 * <tt>null</tt> if there was no mapping for <tt>key</tt>
1052 * @throws NullPointerException if the specified key or value is null
1053 */
1054 @SuppressWarnings("unchecked")
1055 public V put(K key, V value) {
1056 Segment<K,V> s;
1057 if (value == null)
1058 throw new NullPointerException();
1059 int hash = hash(key.hashCode());
1060 int j = (hash >>> segmentShift) & segmentMask;
1061 if ((s = (Segment<K,V>)UNSAFE.getObject // nonvolatile; recheck
1062 (segments, (j << SSHIFT) + SBASE)) == null) // in ensureSegment
1063 s = ensureSegment(j);
1064 return s.put(key, hash, value, false);
1065 }
1066
1067 /**
1068 * {@inheritDoc}
1069 *
1070 * @return the previous value associated with the specified key,
1071 * or <tt>null</tt> if there was no mapping for the key
1072 * @throws NullPointerException if the specified key or value is null
1073 */
1074 @SuppressWarnings("unchecked")
1075 public V putIfAbsent(K key, V value) {
1076 Segment<K,V> s;
1077 if (value == null)
1078 throw new NullPointerException();
1079 int hash = hash(key.hashCode());
1080 int j = (hash >>> segmentShift) & segmentMask;
1081 if ((s = (Segment<K,V>)UNSAFE.getObject
1082 (segments, (j << SSHIFT) + SBASE)) == null)
1083 s = ensureSegment(j);
1084 return s.put(key, hash, value, true);
1085 }
1086
1087 /**
1088 * Copies all of the mappings from the specified map to this one.
1089 * These mappings replace any mappings that this map had for any of the
1090 * keys currently in the specified map.
1091 *
1092 * @param m mappings to be stored in this map
1093 */
1094 public void putAll(Map<? extends K, ? extends V> m) {
1095 for (Map.Entry<? extends K, ? extends V> e : m.entrySet())
1096 put(e.getKey(), e.getValue());
1097 }
1098
1099 /**
1100 * Removes the key (and its corresponding value) from this map.
1101 * This method does nothing if the key is not in the map.
1102 *
1103 * @param key the key that needs to be removed
1104 * @return the previous value associated with <tt>key</tt>, or
1105 * <tt>null</tt> if there was no mapping for <tt>key</tt>
1106 * @throws NullPointerException if the specified key is null
1107 */
1108 public V remove(Object key) {
1109 int hash = hash(key.hashCode());
1110 Segment<K,V> s = segmentForHash(hash);
1111 return s == null ? null : s.remove(key, hash, null);
1112 }
1113
1114 /**
1115 * {@inheritDoc}
1116 *
1117 * @throws NullPointerException if the specified key is null
1118 */
1119 public boolean remove(Object key, Object value) {
1120 int hash = hash(key.hashCode());
1121 Segment<K,V> s;
1122 return value != null && (s = segmentForHash(hash)) != null &&
1123 s.remove(key, hash, value) != null;
1124 }
1125
1126 /**
1127 * {@inheritDoc}
1128 *
1129 * @throws NullPointerException if any of the arguments are null
1130 */
1131 public boolean replace(K key, V oldValue, V newValue) {
1132 int hash = hash(key.hashCode());
1133 if (oldValue == null || newValue == null)
1134 throw new NullPointerException();
1135 Segment<K,V> s = segmentForHash(hash);
1136 return s != null && s.replace(key, hash, oldValue, newValue);
1137 }
1138
1139 /**
1140 * {@inheritDoc}
1141 *
1142 * @return the previous value associated with the specified key,
1143 * or <tt>null</tt> if there was no mapping for the key
1144 * @throws NullPointerException if the specified key or value is null
1145 */
1146 public V replace(K key, V value) {
1147 int hash = hash(key.hashCode());
1148 if (value == null)
1149 throw new NullPointerException();
1150 Segment<K,V> s = segmentForHash(hash);
1151 return s == null ? null : s.replace(key, hash, value);
1152 }
1153
1154 /**
1155 * Removes all of the mappings from this map.
1156 */
1157 public void clear() {
1158 final Segment<K,V>[] segments = this.segments;
1159 for (int j = 0; j < segments.length; ++j) {
1160 Segment<K,V> s = segmentAt(segments, j);
1161 if (s != null)
1162 s.clear();
1163 }
1164 }
1165
1166 /**
1167 * Returns a {@link Set} view of the keys contained in this map.
1455 }
1456 }
1457 } finally {
1458 seg.unlock();
1459 }
1460 }
1461 s.writeObject(null);
1462 s.writeObject(null);
1463 }
1464
1465 /**
1466 * Reconstitute the <tt>ConcurrentHashMap</tt> instance from a
1467 * stream (i.e., deserialize it).
1468 * @param s the stream
1469 */
1470 @SuppressWarnings("unchecked")
1471 private void readObject(java.io.ObjectInputStream s)
1472 throws IOException, ClassNotFoundException {
1473 s.defaultReadObject();
1474
1475 // Re-initialize segments to be minimally sized, and let grow.
1476 int cap = MIN_SEGMENT_TABLE_CAPACITY;
1477 final Segment<K,V>[] segments = this.segments;
1478 for (int k = 0; k < segments.length; ++k) {
1479 Segment<K,V> seg = segments[k];
1480 if (seg != null) {
1481 seg.threshold = (int)(cap * seg.loadFactor);
1482 seg.table = (HashEntry<K,V>[]) new HashEntry[cap];
1483 }
1484 }
1485
1486 // Read the keys and values, and put the mappings in the table
1487 for (;;) {
1488 K key = (K) s.readObject();
1489 V value = (V) s.readObject();
1490 if (key == null)
1491 break;
1492 put(key, value);
1493 }
1494 }
1495
1496 // Unsafe mechanics
1497 private static final sun.misc.Unsafe UNSAFE;
1498 private static final long SBASE;
1499 private static final int SSHIFT;
1500 private static final long TBASE;
1501 private static final int TSHIFT;
1502
1503 static {
1504 int ss, ts;
1505 try {
1506 UNSAFE = sun.misc.Unsafe.getUnsafe();
1507 Class tc = HashEntry[].class;
1508 Class sc = Segment[].class;
1509 TBASE = UNSAFE.arrayBaseOffset(tc);
1510 SBASE = UNSAFE.arrayBaseOffset(sc);
1511 ts = UNSAFE.arrayIndexScale(tc);
1512 ss = UNSAFE.arrayIndexScale(sc);
1513 } catch (Exception e) {
1514 throw new Error(e);
1515 }
1516 if ((ss & (ss-1)) != 0 || (ts & (ts-1)) != 0)
1517 throw new Error("data type scale not a power of two");
1518 SSHIFT = 31 - Integer.numberOfLeadingZeros(ss);
1519 TSHIFT = 31 - Integer.numberOfLeadingZeros(ts);
1520 }
1521
1522 }
|
161 */
162 static final int MIN_SEGMENT_TABLE_CAPACITY = 2;
163
164 /**
165 * The maximum number of segments to allow; used to bound
166 * constructor arguments. Must be power of two less than 1 << 24.
167 */
168 static final int MAX_SEGMENTS = 1 << 16; // slightly conservative
169
170 /**
171 * Number of unsynchronized retries in size and containsValue
172 * methods before resorting to locking. This is used to avoid
173 * unbounded retries if tables undergo continuous modification
174 * which would make it impossible to obtain an accurate result.
175 */
176 static final int RETRIES_BEFORE_LOCK = 2;
177
178 /* ---------------- Fields -------------- */
179
180 /**
181 * holds values which can't be initialized until after VM is booted.
182 */
183 private static class Holder {
184
185 /**
186 * Enable alternate hashing?
187 */
188 static final boolean ALTERNATE_HASHING;
189
190 static {
191 String altThreshold = java.security.AccessController.doPrivileged(
192 new sun.security.action.GetPropertyAction(
193 "jdk.map.althashing.threshold"));
194
195 int threshold;
196 try {
197 threshold = (null != altThreshold)
198 ? Integer.parseInt(altThreshold)
199 : 1;
200
201 if(threshold == -1) {
202 threshold = Integer.MAX_VALUE;
203 }
204
205 if(threshold < 0) {
206 throw new IllegalArgumentException("value must be positive integer.");
207 }
208 } catch(IllegalArgumentException failed) {
209 throw new Error("Illegal value for 'jdk.map.althashing.threshold'", failed);
210 }
211 ALTERNATE_HASHING = threshold <= MAXIMUM_CAPACITY;
212 }
213 }
214
215 /**
216 * A random mask value that is used for hashcode values associated with this
217 * instance to make hash collisions harder to find.
218 */
219 private transient final int hashMask = makeHashMask(this);
220
221 private static int makeHashMask(ConcurrentHashMap instance) {
222 if (sun.misc.VM.isBooted() && Holder.ALTERNATE_HASHING) {
223 return sun.misc.Hashing.makeHashMask(instance);
224 }
225
226 return 0;
227 }
228
229 /**
230 * Mask value for indexing into segments. The upper bits of a
231 * key's hash code are used to choose the segment.
232 */
233 final int segmentMask;
234
235 /**
236 * Shift value for indexing within segments.
237 */
238 final int segmentShift;
239
240 /**
241 * The segments, each of which is a specialized hash table.
242 */
243 final Segment<K,V>[] segments;
244
245 transient Set<K> keySet;
246 transient Set<Map.Entry<K,V>> entrySet;
247 transient Collection<V> values;
248
249 /**
297 (HashEntry<K,V>) UNSAFE.getObjectVolatile
298 (tab, ((long)i << TSHIFT) + TBASE);
299 }
300
301 /**
302 * Sets the ith element of given table, with volatile write
303 * semantics. (See above about use of putOrderedObject.)
304 */
305 static final <K,V> void setEntryAt(HashEntry<K,V>[] tab, int i,
306 HashEntry<K,V> e) {
307 UNSAFE.putOrderedObject(tab, ((long)i << TSHIFT) + TBASE, e);
308 }
309
310 /**
311 * Applies a supplemental hash function to a given hashCode, which
312 * defends against poor quality hash functions. This is critical
313 * because ConcurrentHashMap uses power-of-two length hash tables,
314 * that otherwise encounter collisions for hashCodes that do not
315 * differ in lower or upper bits.
316 */
317 private int hash(Object k) {
318 int h = hashMask;
319
320 if ((0 != h) && (k instanceof String)) {
321 return sun.misc.Hashing.stringHash32((String) k) ^ h;
322 }
323
324 h ^= k.hashCode();
325
326 // Spread bits to regularize both segment and index locations,
327 // using variant of single-word Wang/Jenkins hash.
328 h += (h << 15) ^ 0xffffcd7d;
329 h ^= (h >>> 10);
330 h += (h << 3);
331 h ^= (h >>> 6);
332 h += (h << 2) + (h << 14);
333 return h ^ (h >>> 16);
334 }
335
336 /**
337 * Segments are specialized versions of hash tables. This
338 * subclasses from ReentrantLock opportunistically, just to
339 * simplify some locking and avoid separate construction.
340 */
341 static final class Segment<K,V> extends ReentrantLock implements Serializable {
342 /*
343 * Segments maintain a table of entry lists that are always
344 * kept in a consistent state, so can be read (via volatile
345 * reads of segments and tables) without locking. This
959 segmentAt(segments, j).unlock();
960 }
961 }
962 return overflow ? Integer.MAX_VALUE : size;
963 }
964
965 /**
966 * Returns the value to which the specified key is mapped,
967 * or {@code null} if this map contains no mapping for the key.
968 *
969 * <p>More formally, if this map contains a mapping from a key
970 * {@code k} to a value {@code v} such that {@code key.equals(k)},
971 * then this method returns {@code v}; otherwise it returns
972 * {@code null}. (There can be at most one such mapping.)
973 *
974 * @throws NullPointerException if the specified key is null
975 */
976 public V get(Object key) {
977 Segment<K,V> s; // manually integrate access methods to reduce overhead
978 HashEntry<K,V>[] tab;
979 int h = hash(key);
980 long u = (((h >>> segmentShift) & segmentMask) << SSHIFT) + SBASE;
981 if ((s = (Segment<K,V>)UNSAFE.getObjectVolatile(segments, u)) != null &&
982 (tab = s.table) != null) {
983 for (HashEntry<K,V> e = (HashEntry<K,V>) UNSAFE.getObjectVolatile
984 (tab, ((long)(((tab.length - 1) & h)) << TSHIFT) + TBASE);
985 e != null; e = e.next) {
986 K k;
987 if ((k = e.key) == key || (e.hash == h && key.equals(k)))
988 return e.value;
989 }
990 }
991 return null;
992 }
993
994 /**
995 * Tests if the specified object is a key in this table.
996 *
997 * @param key possible key
998 * @return <tt>true</tt> if and only if the specified object
999 * is a key in this table, as determined by the
1000 * <tt>equals</tt> method; <tt>false</tt> otherwise.
1001 * @throws NullPointerException if the specified key is null
1002 */
1003 @SuppressWarnings("unchecked")
1004 public boolean containsKey(Object key) {
1005 Segment<K,V> s; // same as get() except no need for volatile value read
1006 HashEntry<K,V>[] tab;
1007 int h = hash(key);
1008 long u = (((h >>> segmentShift) & segmentMask) << SSHIFT) + SBASE;
1009 if ((s = (Segment<K,V>)UNSAFE.getObjectVolatile(segments, u)) != null &&
1010 (tab = s.table) != null) {
1011 for (HashEntry<K,V> e = (HashEntry<K,V>) UNSAFE.getObjectVolatile
1012 (tab, ((long)(((tab.length - 1) & h)) << TSHIFT) + TBASE);
1013 e != null; e = e.next) {
1014 K k;
1015 if ((k = e.key) == key || (e.hash == h && key.equals(k)))
1016 return true;
1017 }
1018 }
1019 return false;
1020 }
1021
1022 /**
1023 * Returns <tt>true</tt> if this map maps one or more keys to the
1024 * specified value. Note: This method requires a full internal
1025 * traversal of the hash table, and so is much slower than
1026 * method <tt>containsKey</tt>.
1027 *
1096 }
1097
1098 /**
1099 * Maps the specified key to the specified value in this table.
1100 * Neither the key nor the value can be null.
1101 *
1102 * <p> The value can be retrieved by calling the <tt>get</tt> method
1103 * with a key that is equal to the original key.
1104 *
1105 * @param key key with which the specified value is to be associated
1106 * @param value value to be associated with the specified key
1107 * @return the previous value associated with <tt>key</tt>, or
1108 * <tt>null</tt> if there was no mapping for <tt>key</tt>
1109 * @throws NullPointerException if the specified key or value is null
1110 */
1111 @SuppressWarnings("unchecked")
1112 public V put(K key, V value) {
1113 Segment<K,V> s;
1114 if (value == null)
1115 throw new NullPointerException();
1116 int hash = hash(key);
1117 int j = (hash >>> segmentShift) & segmentMask;
1118 if ((s = (Segment<K,V>)UNSAFE.getObject // nonvolatile; recheck
1119 (segments, (j << SSHIFT) + SBASE)) == null) // in ensureSegment
1120 s = ensureSegment(j);
1121 return s.put(key, hash, value, false);
1122 }
1123
1124 /**
1125 * {@inheritDoc}
1126 *
1127 * @return the previous value associated with the specified key,
1128 * or <tt>null</tt> if there was no mapping for the key
1129 * @throws NullPointerException if the specified key or value is null
1130 */
1131 @SuppressWarnings("unchecked")
1132 public V putIfAbsent(K key, V value) {
1133 Segment<K,V> s;
1134 if (value == null)
1135 throw new NullPointerException();
1136 int hash = hash(key);
1137 int j = (hash >>> segmentShift) & segmentMask;
1138 if ((s = (Segment<K,V>)UNSAFE.getObject
1139 (segments, (j << SSHIFT) + SBASE)) == null)
1140 s = ensureSegment(j);
1141 return s.put(key, hash, value, true);
1142 }
1143
1144 /**
1145 * Copies all of the mappings from the specified map to this one.
1146 * These mappings replace any mappings that this map had for any of the
1147 * keys currently in the specified map.
1148 *
1149 * @param m mappings to be stored in this map
1150 */
1151 public void putAll(Map<? extends K, ? extends V> m) {
1152 for (Map.Entry<? extends K, ? extends V> e : m.entrySet())
1153 put(e.getKey(), e.getValue());
1154 }
1155
1156 /**
1157 * Removes the key (and its corresponding value) from this map.
1158 * This method does nothing if the key is not in the map.
1159 *
1160 * @param key the key that needs to be removed
1161 * @return the previous value associated with <tt>key</tt>, or
1162 * <tt>null</tt> if there was no mapping for <tt>key</tt>
1163 * @throws NullPointerException if the specified key is null
1164 */
1165 public V remove(Object key) {
1166 int hash = hash(key);
1167 Segment<K,V> s = segmentForHash(hash);
1168 return s == null ? null : s.remove(key, hash, null);
1169 }
1170
1171 /**
1172 * {@inheritDoc}
1173 *
1174 * @throws NullPointerException if the specified key is null
1175 */
1176 public boolean remove(Object key, Object value) {
1177 int hash = hash(key);
1178 Segment<K,V> s;
1179 return value != null && (s = segmentForHash(hash)) != null &&
1180 s.remove(key, hash, value) != null;
1181 }
1182
1183 /**
1184 * {@inheritDoc}
1185 *
1186 * @throws NullPointerException if any of the arguments are null
1187 */
1188 public boolean replace(K key, V oldValue, V newValue) {
1189 int hash = hash(key);
1190 if (oldValue == null || newValue == null)
1191 throw new NullPointerException();
1192 Segment<K,V> s = segmentForHash(hash);
1193 return s != null && s.replace(key, hash, oldValue, newValue);
1194 }
1195
1196 /**
1197 * {@inheritDoc}
1198 *
1199 * @return the previous value associated with the specified key,
1200 * or <tt>null</tt> if there was no mapping for the key
1201 * @throws NullPointerException if the specified key or value is null
1202 */
1203 public V replace(K key, V value) {
1204 int hash = hash(key);
1205 if (value == null)
1206 throw new NullPointerException();
1207 Segment<K,V> s = segmentForHash(hash);
1208 return s == null ? null : s.replace(key, hash, value);
1209 }
1210
1211 /**
1212 * Removes all of the mappings from this map.
1213 */
1214 public void clear() {
1215 final Segment<K,V>[] segments = this.segments;
1216 for (int j = 0; j < segments.length; ++j) {
1217 Segment<K,V> s = segmentAt(segments, j);
1218 if (s != null)
1219 s.clear();
1220 }
1221 }
1222
1223 /**
1224 * Returns a {@link Set} view of the keys contained in this map.
1512 }
1513 }
1514 } finally {
1515 seg.unlock();
1516 }
1517 }
1518 s.writeObject(null);
1519 s.writeObject(null);
1520 }
1521
1522 /**
1523 * Reconstitute the <tt>ConcurrentHashMap</tt> instance from a
1524 * stream (i.e., deserialize it).
1525 * @param s the stream
1526 */
1527 @SuppressWarnings("unchecked")
1528 private void readObject(java.io.ObjectInputStream s)
1529 throws IOException, ClassNotFoundException {
1530 s.defaultReadObject();
1531
1532 // set hashMask
1533 UNSAFE.putIntVolatile(this, HASHMASK_OFFSET, makeHashMask(this));
1534
1535 // Re-initialize segments to be minimally sized, and let grow.
1536 int cap = MIN_SEGMENT_TABLE_CAPACITY;
1537 final Segment<K,V>[] segments = this.segments;
1538 for (int k = 0; k < segments.length; ++k) {
1539 Segment<K,V> seg = segments[k];
1540 if (seg != null) {
1541 seg.threshold = (int)(cap * seg.loadFactor);
1542 seg.table = (HashEntry<K,V>[]) new HashEntry[cap];
1543 }
1544 }
1545
1546 // Read the keys and values, and put the mappings in the table
1547 for (;;) {
1548 K key = (K) s.readObject();
1549 V value = (V) s.readObject();
1550 if (key == null)
1551 break;
1552 put(key, value);
1553 }
1554 }
1555
1556 // Unsafe mechanics
1557 private static final sun.misc.Unsafe UNSAFE;
1558 private static final long SBASE;
1559 private static final int SSHIFT;
1560 private static final long TBASE;
1561 private static final int TSHIFT;
1562 private static final long HASHMASK_OFFSET;
1563
1564 static {
1565 int ss, ts;
1566 try {
1567 UNSAFE = sun.misc.Unsafe.getUnsafe();
1568 Class tc = HashEntry[].class;
1569 Class sc = Segment[].class;
1570 TBASE = UNSAFE.arrayBaseOffset(tc);
1571 SBASE = UNSAFE.arrayBaseOffset(sc);
1572 ts = UNSAFE.arrayIndexScale(tc);
1573 ss = UNSAFE.arrayIndexScale(sc);
1574 HASHMASK_OFFSET = UNSAFE.objectFieldOffset(
1575 ConcurrentHashMap.class.getDeclaredField("hashMask"));
1576 } catch (Exception e) {
1577 throw new Error(e);
1578 }
1579 if ((ss & (ss-1)) != 0 || (ts & (ts-1)) != 0)
1580 throw new Error("data type scale not a power of two");
1581 SSHIFT = 31 - Integer.numberOfLeadingZeros(ss);
1582 TSHIFT = 31 - Integer.numberOfLeadingZeros(ts);
1583 }
1584
1585 }
|