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

Print this page
rev 5028 : 7126277: alternative hashing


 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 randomizing value associated with this instance that is applied to  
 217      * hash code of keys to make hash collisions harder to find.
 218      */
 219     private transient final int hashSeed = randomHashSeed(this);
 220     
 221     private static int randomHashSeed(ConcurrentHashMap instance) {
 222         if (sun.misc.VM.isBooted() && Holder.ALTERNATE_HASHING) {
 223             return sun.misc.Hashing.randomHashSeed(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 = hashSeed;
 319 
 320         if ((0 != h) && (k instanceof String)) {
 321             return h ^ sun.misc.Hashing.stringHash32((String) k);
 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, HASHSEED_OFFSET, randomHashSeed(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 HASHSEED_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             HASHSEED_OFFSET = UNSAFE.objectFieldOffset(
1575                 ConcurrentHashMap.class.getDeclaredField("hashSeed"));                        
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 }