src/share/classes/java/util/concurrent/ConcurrentHashMap.java

Print this page
rev 5380 : 7126277: Alternative hashing implementation


 158      */
 159     static final int MIN_SEGMENT_TABLE_CAPACITY = 2;
 160 
 161     /**
 162      * The maximum number of segments to allow; used to bound
 163      * constructor arguments. Must be power of two less than 1 << 24.
 164      */
 165     static final int MAX_SEGMENTS = 1 << 16; // slightly conservative
 166 
 167     /**
 168      * Number of unsynchronized retries in size and containsValue
 169      * methods before resorting to locking. This is used to avoid
 170      * unbounded retries if tables undergo continuous modification
 171      * which would make it impossible to obtain an accurate result.
 172      */
 173     static final int RETRIES_BEFORE_LOCK = 2;
 174 
 175     /* ---------------- Fields -------------- */
 176 
 177     /**






 178      * Mask value for indexing into segments. The upper bits of a
 179      * key's hash code are used to choose the segment.
 180      */
 181     final int segmentMask;
 182 
 183     /**
 184      * Shift value for indexing within segments.
 185      */
 186     final int segmentShift;
 187 
 188     /**
 189      * The segments, each of which is a specialized hash table.
 190      */
 191     final Segment<K,V>[] segments;
 192 
 193     transient Set<K> keySet;
 194     transient Set<Map.Entry<K,V>> entrySet;
 195     transient Collection<V> values;
 196 
 197     /**


 245             (HashEntry<K,V>) UNSAFE.getObjectVolatile
 246             (tab, ((long)i << TSHIFT) + TBASE);
 247     }
 248 
 249     /**
 250      * Sets the ith element of given table, with volatile write
 251      * semantics. (See above about use of putOrderedObject.)
 252      */
 253     static final <K,V> void setEntryAt(HashEntry<K,V>[] tab, int i,
 254                                        HashEntry<K,V> e) {
 255         UNSAFE.putOrderedObject(tab, ((long)i << TSHIFT) + TBASE, e);
 256     }
 257 
 258     /**
 259      * Applies a supplemental hash function to a given hashCode, which
 260      * defends against poor quality hash functions.  This is critical
 261      * because ConcurrentHashMap uses power-of-two length hash tables,
 262      * that otherwise encounter collisions for hashCodes that do not
 263      * differ in lower or upper bits.
 264      */
 265     private static int hash(int h) {








 266         // Spread bits to regularize both segment and index locations,
 267         // using variant of single-word Wang/Jenkins hash.
 268         h += (h <<  15) ^ 0xffffcd7d;
 269         h ^= (h >>> 10);
 270         h += (h <<   3);
 271         h ^= (h >>>  6);
 272         h += (h <<   2) + (h << 14);
 273         return h ^ (h >>> 16);
 274     }
 275 
 276     /**
 277      * Segments are specialized versions of hash tables.  This
 278      * subclasses from ReentrantLock opportunistically, just to
 279      * simplify some locking and avoid separate construction.
 280      */
 281     static final class Segment<K,V> extends ReentrantLock implements Serializable {
 282         /*
 283          * Segments maintain a table of entry lists that are always
 284          * kept in a consistent state, so can be read (via volatile
 285          * reads of segments and tables) without locking.  This


 900             }
 901         }
 902         return overflow ? Integer.MAX_VALUE : size;
 903     }
 904 
 905     /**
 906      * Returns the value to which the specified key is mapped,
 907      * or {@code null} if this map contains no mapping for the key.
 908      *
 909      * <p>More formally, if this map contains a mapping from a key
 910      * {@code k} to a value {@code v} such that {@code key.equals(k)},
 911      * then this method returns {@code v}; otherwise it returns
 912      * {@code null}.  (There can be at most one such mapping.)
 913      *
 914      * @throws NullPointerException if the specified key is null
 915      */
 916     @SuppressWarnings("unchecked")
 917     public V get(Object key) {
 918         Segment<K,V> s; // manually integrate access methods to reduce overhead
 919         HashEntry<K,V>[] tab;
 920         int h = hash(key.hashCode());
 921         long u = (((h >>> segmentShift) & segmentMask) << SSHIFT) + SBASE;
 922         if ((s = (Segment<K,V>)UNSAFE.getObjectVolatile(segments, u)) != null &&
 923             (tab = s.table) != null) {
 924             for (HashEntry<K,V> e = (HashEntry<K,V>) UNSAFE.getObjectVolatile
 925                      (tab, ((long)(((tab.length - 1) & h)) << TSHIFT) + TBASE);
 926                  e != null; e = e.next) {
 927                 K k;
 928                 if ((k = e.key) == key || (e.hash == h && key.equals(k)))
 929                     return e.value;
 930             }
 931         }
 932         return null;
 933     }
 934 
 935     /**
 936      * Tests if the specified object is a key in this table.
 937      *
 938      * @param  key   possible key
 939      * @return <tt>true</tt> if and only if the specified object
 940      *         is a key in this table, as determined by the
 941      *         <tt>equals</tt> method; <tt>false</tt> otherwise.
 942      * @throws NullPointerException if the specified key is null
 943      */
 944     @SuppressWarnings("unchecked")
 945     public boolean containsKey(Object key) {
 946         Segment<K,V> s; // same as get() except no need for volatile value read
 947         HashEntry<K,V>[] tab;
 948         int h = hash(key.hashCode());
 949         long u = (((h >>> segmentShift) & segmentMask) << SSHIFT) + SBASE;
 950         if ((s = (Segment<K,V>)UNSAFE.getObjectVolatile(segments, u)) != null &&
 951             (tab = s.table) != null) {
 952             for (HashEntry<K,V> e = (HashEntry<K,V>) UNSAFE.getObjectVolatile
 953                      (tab, ((long)(((tab.length - 1) & h)) << TSHIFT) + TBASE);
 954                  e != null; e = e.next) {
 955                 K k;
 956                 if ((k = e.key) == key || (e.hash == h && key.equals(k)))
 957                     return true;
 958             }
 959         }
 960         return false;
 961     }
 962 
 963     /**
 964      * Returns <tt>true</tt> if this map maps one or more keys to the
 965      * specified value. Note: This method requires a full internal
 966      * traversal of the hash table, and so is much slower than
 967      * method <tt>containsKey</tt>.
 968      *


1037     }
1038 
1039     /**
1040      * Maps the specified key to the specified value in this table.
1041      * Neither the key nor the value can be null.
1042      *
1043      * <p> The value can be retrieved by calling the <tt>get</tt> method
1044      * with a key that is equal to the original key.
1045      *
1046      * @param key key with which the specified value is to be associated
1047      * @param value value to be associated with the specified key
1048      * @return the previous value associated with <tt>key</tt>, or
1049      *         <tt>null</tt> if there was no mapping for <tt>key</tt>
1050      * @throws NullPointerException if the specified key or value is null
1051      */
1052     @SuppressWarnings("unchecked")
1053     public V put(K key, V value) {
1054         Segment<K,V> s;
1055         if (value == null)
1056             throw new NullPointerException();
1057         int hash = hash(key.hashCode());
1058         int j = (hash >>> segmentShift) & segmentMask;
1059         if ((s = (Segment<K,V>)UNSAFE.getObject          // nonvolatile; recheck
1060              (segments, (j << SSHIFT) + SBASE)) == null) //  in ensureSegment
1061             s = ensureSegment(j);
1062         return s.put(key, hash, value, false);
1063     }
1064 
1065     /**
1066      * {@inheritDoc}
1067      *
1068      * @return the previous value associated with the specified key,
1069      *         or <tt>null</tt> if there was no mapping for the key
1070      * @throws NullPointerException if the specified key or value is null
1071      */
1072     @SuppressWarnings("unchecked")
1073     public V putIfAbsent(K key, V value) {
1074         Segment<K,V> s;
1075         if (value == null)
1076             throw new NullPointerException();
1077         int hash = hash(key.hashCode());
1078         int j = (hash >>> segmentShift) & segmentMask;
1079         if ((s = (Segment<K,V>)UNSAFE.getObject
1080              (segments, (j << SSHIFT) + SBASE)) == null)
1081             s = ensureSegment(j);
1082         return s.put(key, hash, value, true);
1083     }
1084 
1085     /**
1086      * Copies all of the mappings from the specified map to this one.
1087      * These mappings replace any mappings that this map had for any of the
1088      * keys currently in the specified map.
1089      *
1090      * @param m mappings to be stored in this map
1091      */
1092     public void putAll(Map<? extends K, ? extends V> m) {
1093         for (Map.Entry<? extends K, ? extends V> e : m.entrySet())
1094             put(e.getKey(), e.getValue());
1095     }
1096 
1097     /**
1098      * Removes the key (and its corresponding value) from this map.
1099      * This method does nothing if the key is not in the map.
1100      *
1101      * @param  key the key that needs to be removed
1102      * @return the previous value associated with <tt>key</tt>, or
1103      *         <tt>null</tt> if there was no mapping for <tt>key</tt>
1104      * @throws NullPointerException if the specified key is null
1105      */
1106     public V remove(Object key) {
1107         int hash = hash(key.hashCode());
1108         Segment<K,V> s = segmentForHash(hash);
1109         return s == null ? null : s.remove(key, hash, null);
1110     }
1111 
1112     /**
1113      * {@inheritDoc}
1114      *
1115      * @throws NullPointerException if the specified key is null
1116      */
1117     public boolean remove(Object key, Object value) {
1118         int hash = hash(key.hashCode());
1119         Segment<K,V> s;
1120         return value != null && (s = segmentForHash(hash)) != null &&
1121             s.remove(key, hash, value) != null;
1122     }
1123 
1124     /**
1125      * {@inheritDoc}
1126      *
1127      * @throws NullPointerException if any of the arguments are null
1128      */
1129     public boolean replace(K key, V oldValue, V newValue) {
1130         int hash = hash(key.hashCode());
1131         if (oldValue == null || newValue == null)
1132             throw new NullPointerException();
1133         Segment<K,V> s = segmentForHash(hash);
1134         return s != null && s.replace(key, hash, oldValue, newValue);
1135     }
1136 
1137     /**
1138      * {@inheritDoc}
1139      *
1140      * @return the previous value associated with the specified key,
1141      *         or <tt>null</tt> if there was no mapping for the key
1142      * @throws NullPointerException if the specified key or value is null
1143      */
1144     public V replace(K key, V value) {
1145         int hash = hash(key.hashCode());
1146         if (value == null)
1147             throw new NullPointerException();
1148         Segment<K,V> s = segmentForHash(hash);
1149         return s == null ? null : s.replace(key, hash, value);
1150     }
1151 
1152     /**
1153      * Removes all of the mappings from this map.
1154      */
1155     public void clear() {
1156         final Segment<K,V>[] segments = this.segments;
1157         for (int j = 0; j < segments.length; ++j) {
1158             Segment<K,V> s = segmentAt(segments, j);
1159             if (s != null)
1160                 s.clear();
1161         }
1162     }
1163 
1164     /**
1165      * Returns a {@link Set} view of the keys contained in this map.


1456                     }
1457                 }
1458             } finally {
1459                 seg.unlock();
1460             }
1461         }
1462         s.writeObject(null);
1463         s.writeObject(null);
1464     }
1465 
1466     /**
1467      * Reconstitutes the <tt>ConcurrentHashMap</tt> instance from a
1468      * stream (i.e., deserializes it).
1469      * @param s the stream
1470      */
1471     @SuppressWarnings("unchecked")
1472     private void readObject(java.io.ObjectInputStream s)
1473             throws java.io.IOException, ClassNotFoundException {
1474         s.defaultReadObject();
1475 




1476         // Re-initialize segments to be minimally sized, and let grow.
1477         int cap = MIN_SEGMENT_TABLE_CAPACITY;
1478         final Segment<K,V>[] segments = this.segments;
1479         for (int k = 0; k < segments.length; ++k) {
1480             Segment<K,V> seg = segments[k];
1481             if (seg != null) {
1482                 seg.threshold = (int)(cap * seg.loadFactor);
1483                 seg.table = (HashEntry<K,V>[]) new HashEntry<?,?>[cap];
1484             }
1485         }
1486 
1487         // Read the keys and values, and put the mappings in the table
1488         for (;;) {
1489             K key = (K) s.readObject();
1490             V value = (V) s.readObject();
1491             if (key == null)
1492                 break;
1493             put(key, value);
1494         }
1495     }
1496 
1497     // Unsafe mechanics
1498     private static final sun.misc.Unsafe UNSAFE;
1499     private static final long SBASE;
1500     private static final int SSHIFT;
1501     private static final long TBASE;
1502     private static final int TSHIFT;

1503 
1504     static {
1505         int ss, ts;
1506         try {
1507             UNSAFE = sun.misc.Unsafe.getUnsafe();
1508             Class<?> tc = HashEntry[].class;
1509             Class<?> sc = Segment[].class;
1510             TBASE = UNSAFE.arrayBaseOffset(tc);
1511             SBASE = UNSAFE.arrayBaseOffset(sc);
1512             ts = UNSAFE.arrayIndexScale(tc);
1513             ss = UNSAFE.arrayIndexScale(sc);


1514         } catch (Exception e) {
1515             throw new Error(e);
1516         }
1517         if ((ss & (ss-1)) != 0 || (ts & (ts-1)) != 0)
1518             throw new Error("data type scale not a power of two");
1519         SSHIFT = 31 - Integer.numberOfLeadingZeros(ss);
1520         TSHIFT = 31 - Integer.numberOfLeadingZeros(ts);
1521     }
1522 
1523 }


 158      */
 159     static final int MIN_SEGMENT_TABLE_CAPACITY = 2;
 160 
 161     /**
 162      * The maximum number of segments to allow; used to bound
 163      * constructor arguments. Must be power of two less than 1 << 24.
 164      */
 165     static final int MAX_SEGMENTS = 1 << 16; // slightly conservative
 166 
 167     /**
 168      * Number of unsynchronized retries in size and containsValue
 169      * methods before resorting to locking. This is used to avoid
 170      * unbounded retries if tables undergo continuous modification
 171      * which would make it impossible to obtain an accurate result.
 172      */
 173     static final int RETRIES_BEFORE_LOCK = 2;
 174 
 175     /* ---------------- Fields -------------- */
 176 
 177     /**
 178      * A random mask value that is used for hashcode values associated with this
 179      * instance to make hash collisions harder to find.
 180      */
 181     private transient final int hashMask = sun.misc.Hashing.makeHashMask(this);
 182     
 183     /**
 184      * Mask value for indexing into segments. The upper bits of a
 185      * key's hash code are used to choose the segment.
 186      */
 187     final int segmentMask;
 188 
 189     /**
 190      * Shift value for indexing within segments.
 191      */
 192     final int segmentShift;
 193 
 194     /**
 195      * The segments, each of which is a specialized hash table.
 196      */
 197     final Segment<K,V>[] segments;
 198 
 199     transient Set<K> keySet;
 200     transient Set<Map.Entry<K,V>> entrySet;
 201     transient Collection<V> values;
 202 
 203     /**


 251             (HashEntry<K,V>) UNSAFE.getObjectVolatile
 252             (tab, ((long)i << TSHIFT) + TBASE);
 253     }
 254 
 255     /**
 256      * Sets the ith element of given table, with volatile write
 257      * semantics. (See above about use of putOrderedObject.)
 258      */
 259     static final <K,V> void setEntryAt(HashEntry<K,V>[] tab, int i,
 260                                        HashEntry<K,V> e) {
 261         UNSAFE.putOrderedObject(tab, ((long)i << TSHIFT) + TBASE, e);
 262     }
 263 
 264     /**
 265      * Applies a supplemental hash function to a given hashCode, which
 266      * defends against poor quality hash functions.  This is critical
 267      * because ConcurrentHashMap uses power-of-two length hash tables,
 268      * that otherwise encounter collisions for hashCodes that do not
 269      * differ in lower or upper bits.
 270      */
 271     private int hash(Object k) {        
 272        int h = hashMask;
 273 
 274         if ((0 != h) && (k instanceof String)) {
 275             return ((String) k).hash32() ^ h;
 276         }
 277 
 278         h ^= k.hashCode();
 279 
 280         // Spread bits to regularize both segment and index locations,
 281         // using variant of single-word Wang/Jenkins hash.
 282         h += (h <<  15) ^ 0xffffcd7d;
 283         h ^= (h >>> 10);
 284         h += (h <<   3);
 285         h ^= (h >>>  6);
 286         h += (h <<   2) + (h << 14);
 287         return h ^ (h >>> 16);
 288     }
 289 
 290     /**
 291      * Segments are specialized versions of hash tables.  This
 292      * subclasses from ReentrantLock opportunistically, just to
 293      * simplify some locking and avoid separate construction.
 294      */
 295     static final class Segment<K,V> extends ReentrantLock implements Serializable {
 296         /*
 297          * Segments maintain a table of entry lists that are always
 298          * kept in a consistent state, so can be read (via volatile
 299          * reads of segments and tables) without locking.  This


 914             }
 915         }
 916         return overflow ? Integer.MAX_VALUE : size;
 917     }
 918 
 919     /**
 920      * Returns the value to which the specified key is mapped,
 921      * or {@code null} if this map contains no mapping for the key.
 922      *
 923      * <p>More formally, if this map contains a mapping from a key
 924      * {@code k} to a value {@code v} such that {@code key.equals(k)},
 925      * then this method returns {@code v}; otherwise it returns
 926      * {@code null}.  (There can be at most one such mapping.)
 927      *
 928      * @throws NullPointerException if the specified key is null
 929      */
 930     @SuppressWarnings("unchecked")
 931     public V get(Object key) {
 932         Segment<K,V> s; // manually integrate access methods to reduce overhead
 933         HashEntry<K,V>[] tab;
 934         int h = hash(key);
 935         long u = (((h >>> segmentShift) & segmentMask) << SSHIFT) + SBASE;
 936         if ((s = (Segment<K,V>)UNSAFE.getObjectVolatile(segments, u)) != null &&
 937             (tab = s.table) != null) {
 938             for (HashEntry<K,V> e = (HashEntry<K,V>) UNSAFE.getObjectVolatile
 939                      (tab, ((long)(((tab.length - 1) & h)) << TSHIFT) + TBASE);
 940                  e != null; e = e.next) {
 941                 K k;
 942                 if ((k = e.key) == key || (e.hash == h && key.equals(k)))
 943                     return e.value;
 944             }
 945         }
 946         return null;
 947     }
 948 
 949     /**
 950      * Tests if the specified object is a key in this table.
 951      *
 952      * @param  key   possible key
 953      * @return <tt>true</tt> if and only if the specified object
 954      *         is a key in this table, as determined by the
 955      *         <tt>equals</tt> method; <tt>false</tt> otherwise.
 956      * @throws NullPointerException if the specified key is null
 957      */
 958     @SuppressWarnings("unchecked")
 959     public boolean containsKey(Object key) {
 960         Segment<K,V> s; // same as get() except no need for volatile value read
 961         HashEntry<K,V>[] tab;
 962         int h = hash(key);
 963         long u = (((h >>> segmentShift) & segmentMask) << SSHIFT) + SBASE;
 964         if ((s = (Segment<K,V>)UNSAFE.getObjectVolatile(segments, u)) != null &&
 965             (tab = s.table) != null) {
 966             for (HashEntry<K,V> e = (HashEntry<K,V>) UNSAFE.getObjectVolatile
 967                      (tab, ((long)(((tab.length - 1) & h)) << TSHIFT) + TBASE);
 968                  e != null; e = e.next) {
 969                 K k;
 970                 if ((k = e.key) == key || (e.hash == h && key.equals(k)))
 971                     return true;
 972             }
 973         }
 974         return false;
 975     }
 976 
 977     /**
 978      * Returns <tt>true</tt> if this map maps one or more keys to the
 979      * specified value. Note: This method requires a full internal
 980      * traversal of the hash table, and so is much slower than
 981      * method <tt>containsKey</tt>.
 982      *


1051     }
1052 
1053     /**
1054      * Maps the specified key to the specified value in this table.
1055      * Neither the key nor the value can be null.
1056      *
1057      * <p> The value can be retrieved by calling the <tt>get</tt> method
1058      * with a key that is equal to the original key.
1059      *
1060      * @param key key with which the specified value is to be associated
1061      * @param value value to be associated with the specified key
1062      * @return the previous value associated with <tt>key</tt>, or
1063      *         <tt>null</tt> if there was no mapping for <tt>key</tt>
1064      * @throws NullPointerException if the specified key or value is null
1065      */
1066     @SuppressWarnings("unchecked")
1067     public V put(K key, V value) {
1068         Segment<K,V> s;
1069         if (value == null)
1070             throw new NullPointerException();
1071         int hash = hash(key);
1072         int j = (hash >>> segmentShift) & segmentMask;
1073         if ((s = (Segment<K,V>)UNSAFE.getObject          // nonvolatile; recheck
1074              (segments, (j << SSHIFT) + SBASE)) == null) //  in ensureSegment
1075             s = ensureSegment(j);
1076         return s.put(key, hash, value, false);
1077     }
1078 
1079     /**
1080      * {@inheritDoc}
1081      *
1082      * @return the previous value associated with the specified key,
1083      *         or <tt>null</tt> if there was no mapping for the key
1084      * @throws NullPointerException if the specified key or value is null
1085      */
1086     @SuppressWarnings("unchecked")
1087     public V putIfAbsent(K key, V value) {
1088         Segment<K,V> s;
1089         if (value == null)
1090             throw new NullPointerException();
1091         int hash = hash(key);
1092         int j = (hash >>> segmentShift) & segmentMask;
1093         if ((s = (Segment<K,V>)UNSAFE.getObject
1094              (segments, (j << SSHIFT) + SBASE)) == null)
1095             s = ensureSegment(j);
1096         return s.put(key, hash, value, true);
1097     }
1098 
1099     /**
1100      * Copies all of the mappings from the specified map to this one.
1101      * These mappings replace any mappings that this map had for any of the
1102      * keys currently in the specified map.
1103      *
1104      * @param m mappings to be stored in this map
1105      */
1106     public void putAll(Map<? extends K, ? extends V> m) {
1107         for (Map.Entry<? extends K, ? extends V> e : m.entrySet())
1108             put(e.getKey(), e.getValue());
1109     }
1110 
1111     /**
1112      * Removes the key (and its corresponding value) from this map.
1113      * This method does nothing if the key is not in the map.
1114      *
1115      * @param  key the key that needs to be removed
1116      * @return the previous value associated with <tt>key</tt>, or
1117      *         <tt>null</tt> if there was no mapping for <tt>key</tt>
1118      * @throws NullPointerException if the specified key is null
1119      */
1120     public V remove(Object key) {
1121         int hash = hash(key);
1122         Segment<K,V> s = segmentForHash(hash);
1123         return s == null ? null : s.remove(key, hash, null);
1124     }
1125 
1126     /**
1127      * {@inheritDoc}
1128      *
1129      * @throws NullPointerException if the specified key is null
1130      */
1131     public boolean remove(Object key, Object value) {
1132         int hash = hash(key);
1133         Segment<K,V> s;
1134         return value != null && (s = segmentForHash(hash)) != null &&
1135             s.remove(key, hash, value) != null;
1136     }
1137 
1138     /**
1139      * {@inheritDoc}
1140      *
1141      * @throws NullPointerException if any of the arguments are null
1142      */
1143     public boolean replace(K key, V oldValue, V newValue) {
1144         int hash = hash(key);
1145         if (oldValue == null || newValue == null)
1146             throw new NullPointerException();
1147         Segment<K,V> s = segmentForHash(hash);
1148         return s != null && s.replace(key, hash, oldValue, newValue);
1149     }
1150 
1151     /**
1152      * {@inheritDoc}
1153      *
1154      * @return the previous value associated with the specified key,
1155      *         or <tt>null</tt> if there was no mapping for the key
1156      * @throws NullPointerException if the specified key or value is null
1157      */
1158     public V replace(K key, V value) {
1159         int hash = hash(key);
1160         if (value == null)
1161             throw new NullPointerException();
1162         Segment<K,V> s = segmentForHash(hash);
1163         return s == null ? null : s.replace(key, hash, value);
1164     }
1165 
1166     /**
1167      * Removes all of the mappings from this map.
1168      */
1169     public void clear() {
1170         final Segment<K,V>[] segments = this.segments;
1171         for (int j = 0; j < segments.length; ++j) {
1172             Segment<K,V> s = segmentAt(segments, j);
1173             if (s != null)
1174                 s.clear();
1175         }
1176     }
1177 
1178     /**
1179      * Returns a {@link Set} view of the keys contained in this map.


1470                     }
1471                 }
1472             } finally {
1473                 seg.unlock();
1474             }
1475         }
1476         s.writeObject(null);
1477         s.writeObject(null);
1478     }
1479 
1480     /**
1481      * Reconstitutes the <tt>ConcurrentHashMap</tt> instance from a
1482      * stream (i.e., deserializes it).
1483      * @param s the stream
1484      */
1485     @SuppressWarnings("unchecked")
1486     private void readObject(java.io.ObjectInputStream s)
1487             throws java.io.IOException, ClassNotFoundException {
1488         s.defaultReadObject();
1489         
1490         // set hashMask
1491         UNSAFE.putIntVolatile(this, HASHMASK_OFFSET, 
1492                  sun.misc.Hashing.makeHashMask(this));
1493 
1494         // Re-initialize segments to be minimally sized, and let grow.
1495         int cap = MIN_SEGMENT_TABLE_CAPACITY;
1496         final Segment<K,V>[] segments = this.segments;
1497         for (int k = 0; k < segments.length; ++k) {
1498             Segment<K,V> seg = segments[k];
1499             if (seg != null) {
1500                 seg.threshold = (int)(cap * seg.loadFactor);
1501                 seg.table = (HashEntry<K,V>[]) new HashEntry<?,?>[cap];
1502             }
1503         }
1504 
1505         // Read the keys and values, and put the mappings in the table
1506         for (;;) {
1507             K key = (K) s.readObject();
1508             V value = (V) s.readObject();
1509             if (key == null)
1510                 break;
1511             put(key, value);
1512         }
1513     }
1514 
1515     // Unsafe mechanics
1516     private static final sun.misc.Unsafe UNSAFE;
1517     private static final long SBASE;
1518     private static final int SSHIFT;
1519     private static final long TBASE;
1520     private static final int TSHIFT;
1521     private static final long HASHMASK_OFFSET;
1522 
1523     static {
1524         int ss, ts;
1525         try {
1526             UNSAFE = sun.misc.Unsafe.getUnsafe();
1527             Class<?> tc = HashEntry[].class;
1528             Class<?> sc = Segment[].class;
1529             TBASE = UNSAFE.arrayBaseOffset(tc);
1530             SBASE = UNSAFE.arrayBaseOffset(sc);
1531             ts = UNSAFE.arrayIndexScale(tc);
1532             ss = UNSAFE.arrayIndexScale(sc);
1533             HASHMASK_OFFSET = UNSAFE.objectFieldOffset(
1534                 ConcurrentHashMap.class.getDeclaredField("hashMask"));                        
1535         } catch (Exception e) {
1536             throw new Error(e);
1537         }
1538         if ((ss & (ss-1)) != 0 || (ts & (ts-1)) != 0)
1539             throw new Error("data type scale not a power of two");
1540         SSHIFT = 31 - Integer.numberOfLeadingZeros(ss);
1541         TSHIFT = 31 - Integer.numberOfLeadingZeros(ts);
1542     }
1543 
1544 }