8009063: Improve reliability of ConcurrentHashMap
authorchegar
Sun, 03 Mar 2013 10:07:52 +0000
changeset 16883 8c290711866f
parent 16882 c9b0f63bb215
child 16884 e745e337f767
8009063: Improve reliability of ConcurrentHashMap Reviewed-by: alanb, ahgross
jdk/src/share/classes/java/util/concurrent/ConcurrentHashMap.java
--- a/jdk/src/share/classes/java/util/concurrent/ConcurrentHashMap.java	Tue Feb 26 01:41:36 2013 +0400
+++ b/jdk/src/share/classes/java/util/concurrent/ConcurrentHashMap.java	Sun Mar 03 10:07:52 2013 +0000
@@ -34,6 +34,7 @@
  */
 
 package java.util.concurrent;
+import java.io.ObjectInputStream;
 import java.util.concurrent.locks.*;
 import java.util.*;
 import java.io.Serializable;
@@ -1483,7 +1484,23 @@
     @SuppressWarnings("unchecked")
     private void readObject(java.io.ObjectInputStream s)
             throws java.io.IOException, ClassNotFoundException {
-        s.defaultReadObject();
+        // Don't call defaultReadObject()
+        ObjectInputStream.GetField oisFields = s.readFields();
+        final Segment<K,V>[] oisSegments = (Segment<K,V>[])oisFields.get("segments", null);
+
+        final int ssize = oisSegments.length;
+        if (ssize < 1 || ssize > MAX_SEGMENTS
+            || (ssize & (ssize-1)) != 0 )  // ssize not power of two
+            throw new java.io.InvalidObjectException("Bad number of segments:"
+                                                     + ssize);
+        int sshift = 0, ssizeTmp = ssize;
+        while (ssizeTmp > 1) {
+            ++sshift;
+            ssizeTmp >>>= 1;
+        }
+        UNSAFE.putIntVolatile(this, SEGSHIFT_OFFSET, 32 - sshift);
+        UNSAFE.putIntVolatile(this, SEGMASK_OFFSET, ssize - 1);
+        UNSAFE.putObjectVolatile(this, SEGMENTS_OFFSET, oisSegments);
 
         // set hashMask
         UNSAFE.putIntVolatile(this, HASHSEED_OFFSET,
@@ -1517,6 +1534,9 @@
     private static final long TBASE;
     private static final int TSHIFT;
     private static final long HASHSEED_OFFSET;
+    private static final long SEGSHIFT_OFFSET;
+    private static final long SEGMASK_OFFSET;
+    private static final long SEGMENTS_OFFSET;
 
     static {
         int ss, ts;
@@ -1530,6 +1550,12 @@
             ss = UNSAFE.arrayIndexScale(sc);
             HASHSEED_OFFSET = UNSAFE.objectFieldOffset(
                 ConcurrentHashMap.class.getDeclaredField("hashSeed"));
+            SEGSHIFT_OFFSET = UNSAFE.objectFieldOffset(
+                ConcurrentHashMap.class.getDeclaredField("segmentShift"));
+            SEGMASK_OFFSET = UNSAFE.objectFieldOffset(
+                ConcurrentHashMap.class.getDeclaredField("segmentMask"));
+            SEGMENTS_OFFSET = UNSAFE.objectFieldOffset(
+                ConcurrentHashMap.class.getDeclaredField("segments"));
         } catch (Exception e) {
             throw new Error(e);
         }