--- jsr166/src/jsr166e/extra/AtomicDoubleArray.java 2011/10/20 16:33:25 1.2 +++ jsr166/src/jsr166e/extra/AtomicDoubleArray.java 2013/03/04 15:21:23 1.8 @@ -14,13 +14,13 @@ import static java.lang.Double.longBitsT * See the {@link java.util.concurrent.atomic} package specification * for description of the properties of atomic variables. * - *

This class compares primitive {@code double} + *

This class compares primitive {@code double} * values in methods such as {@link #compareAndSet} by comparing their * bitwise representation using {@link Double#doubleToRawLongBits}, * which differs from both the primitive double {@code ==} operator * and from {@link Double#equals}, as if implemented by: *

 {@code
- * boolean bitEquals(double x, double y) {
+ * static boolean bitEquals(double x, double y) {
  *   long xBits = Double.doubleToRawLongBits(x);
  *   long yBits = Double.doubleToRawLongBits(y);
  *   return xBits == yBits;
@@ -32,7 +32,7 @@ import static java.lang.Double.longBitsT
 public class AtomicDoubleArray implements java.io.Serializable {
     private static final long serialVersionUID = -2308431214976778248L;
 
-    private final long[] array;
+    private final transient long[] array;
 
     private long checkedByteOffset(int i) {
         if (i < 0 || i >= array.length)
@@ -235,16 +235,59 @@ public class AtomicDoubleArray implement
         }
     }
 
+    /**
+     * Saves the state to a stream (that is, serializes it).
+     *
+     * @serialData The length of the array is emitted (int), followed by all
+     *             of its elements (each a {@code double}) in the proper order.
+     */
+    private void writeObject(java.io.ObjectOutputStream s)
+        throws java.io.IOException {
+        s.defaultWriteObject();
+
+        // Write out array length
+        int length = length();
+        s.writeInt(length);
+
+        // Write out all elements in the proper order.
+        for (int i = 0; i < length; i++)
+            s.writeDouble(get(i));
+    }
+
+    /**
+     * Reconstitutes the instance from a stream (that is, deserializes it).
+     */
+    private void readObject(java.io.ObjectInputStream s)
+        throws java.io.IOException, ClassNotFoundException {
+        s.defaultReadObject();
+
+        // Read in array length and allocate array
+        int length = s.readInt();
+        unsafe.putObjectVolatile(this, arrayOffset, new long[length]);
+
+        // Read in all elements in the proper order.
+        for (int i = 0; i < length; i++)
+            set(i, s.readDouble());
+    }
+
     // Unsafe mechanics
     private static final sun.misc.Unsafe unsafe = getUnsafe();
+    private static final long arrayOffset;
     private static final int base = unsafe.arrayBaseOffset(long[].class);
     private static final int shift;
 
     static {
-        int scale = unsafe.arrayIndexScale(long[].class);
-        if ((scale & (scale - 1)) != 0)
-            throw new Error("data type scale not a power of two");
-        shift = 31 - Integer.numberOfLeadingZeros(scale);
+        try {
+            Class k = AtomicDoubleArray.class;
+            arrayOffset = unsafe.objectFieldOffset
+                (k.getDeclaredField("array"));
+            int scale = unsafe.arrayIndexScale(long[].class);
+            if ((scale & (scale - 1)) != 0)
+                throw new Error("data type scale not a power of two");
+            shift = 31 - Integer.numberOfLeadingZeros(scale);
+        } catch (Exception e) {
+            throw new Error(e);
+        }
     }
 
     /**
@@ -257,21 +300,23 @@ public class AtomicDoubleArray implement
     private static sun.misc.Unsafe getUnsafe() {
         try {
             return sun.misc.Unsafe.getUnsafe();
-        } catch (SecurityException se) {
-            try {
-                return java.security.AccessController.doPrivileged
-                    (new java.security
-                     .PrivilegedExceptionAction() {
-                        public sun.misc.Unsafe run() throws Exception {
-                            java.lang.reflect.Field f = sun.misc
-                                .Unsafe.class.getDeclaredField("theUnsafe");
-                            f.setAccessible(true);
-                            return (sun.misc.Unsafe) f.get(null);
-                        }});
-            } catch (java.security.PrivilegedActionException e) {
-                throw new RuntimeException("Could not initialize intrinsics",
-                                           e.getCause());
-            }
+        } catch (SecurityException tryReflectionInstead) {}
+        try {
+            return java.security.AccessController.doPrivileged
+            (new java.security.PrivilegedExceptionAction() {
+                public sun.misc.Unsafe run() throws Exception {
+                    Class k = sun.misc.Unsafe.class;
+                    for (java.lang.reflect.Field f : k.getDeclaredFields()) {
+                        f.setAccessible(true);
+                        Object x = f.get(null);
+                        if (k.isInstance(x))
+                            return k.cast(x);
+                    }
+                    throw new NoSuchFieldError("the Unsafe");
+                }});
+        } catch (java.security.PrivilegedActionException e) {
+            throw new RuntimeException("Could not initialize intrinsics",
+                                       e.getCause());
         }
     }
 }