--- jsr166/src/jsr166e/extra/AtomicDoubleArray.java 2011/08/10 02:03:29 1.1 +++ jsr166/src/jsr166e/extra/AtomicDoubleArray.java 2013/03/04 16:09:25 1.9 @@ -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)
@@ -162,9 +162,11 @@ public class AtomicDoubleArray implement
      * if the current value is bitwise equal
      * to the expected value.
      *
-     * 

May fail spuriously - * and does not provide ordering guarantees, so is only rarely an - * appropriate alternative to {@code compareAndSet}. + *

+ + * May fail spuriously and does not provide ordering guarantees, + * so is only rarely an appropriate alternative to {@code compareAndSet}. * * @param i the index * @param expect the expected value @@ -222,9 +224,10 @@ public class AtomicDoubleArray implement if (iMax == -1) return "[]"; - StringBuilder b = new StringBuilder(); + // Double.toString(Math.PI).length() == 17 + StringBuilder b = new StringBuilder((17 + 2) * (iMax + 1)); b.append('['); - for (int i = 0; ; i++) { + for (int i = 0;; i++) { b.append(longBitsToDouble(getRaw(byteOffset(i)))); if (i == iMax) return b.append(']').toString(); @@ -232,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); + } } /** @@ -254,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()); } } }