--- jsr166/src/jsr166e/extra/AtomicDouble.java 2011/08/09 04:05:25 1.1 +++ jsr166/src/jsr166e/extra/AtomicDouble.java 2013/01/09 02:51:37 1.14 @@ -1,59 +1,49 @@ /* - * Written by Doug Lea with assistance from members of JCP JSR-166 - * Expert Group and released to the public domain, as explained at + * Written by Doug Lea and Martin Buchholz with assistance from + * members of JCP JSR-166 Expert Group and released to the public + * domain, as explained at * http://creativecommons.org/publicdomain/zero/1.0/ */ package jsr166e.extra; + import static java.lang.Double.doubleToRawLongBits; import static java.lang.Double.longBitsToDouble; -import sun.misc.Unsafe; /** * A {@code double} value that may be updated atomically. See the * {@link java.util.concurrent.atomic} package specification for - * description of the properties of atomic variables. An - * {@code AtomicDouble} is used in applications such as atomically - * incremented sequence numbers, and cannot be used as a replacement - * for a {@link java.lang.Double}. However, this class does extend - * {@code Number} to allow uniform access by tools and utilities that - * deal with numerically-based classes. + * description of the properties of atomic variables. An {@code + * AtomicDouble} is used in applications such as atomic accumulation, + * and cannot be used as a replacement for a {@link Double}. However, + * this class does extend {@code Number} to allow uniform access by + * tools and utilities that deal with numerically-based classes. + * + *

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
+ * static boolean bitEquals(double x, double y) {
+ *   long xBits = Double.doubleToRawLongBits(x);
+ *   long yBits = Double.doubleToRawLongBits(y);
+ *   return xBits == yBits;
+ * }}
+ * + * @see jsr166e.DoubleAdder + * @see jsr166e.DoubleMaxUpdater * - * @since 1.5 * @author Doug Lea + * @author Martin Buchholz */ public class AtomicDouble extends Number implements java.io.Serializable { - private static final long serialVersionUID = 1927816293512124184L; + private static final long serialVersionUID = -8405198993435143622L; - // setup to use Unsafe.compareAndSwapLong for updates - private static final Unsafe unsafe = Unsafe.getUnsafe(); - private static final long valueOffset; - - /** - * Records whether the underlying JVM supports lockless - * compareAndSwap for longs. While the Unsafe.compareAndSwapLong - * method works in either case, some constructions should be - * handled at Java level to avoid locking user-visible locks. - */ - static final boolean VM_SUPPORTS_LONG_CAS = VMSupportsCS8(); + private transient volatile long value; /** - * Returns whether underlying JVM supports lockless CompareAndSet - * for longs. Called only once and cached in VM_SUPPORTS_LONG_CAS. - */ - private static native boolean VMSupportsCS8(); - - static { - try { - valueOffset = unsafe.objectFieldOffset - (AtomicDouble.class.getDeclaredField("value")); - } catch (Exception ex) { throw new Error(ex); } - } - - private volatile long value; - - /** - * Creates a new AtomicDouble with the given initial value. + * Creates a new {@code AtomicDouble} with the given initial value. * * @param initialValue the initial value */ @@ -62,9 +52,11 @@ public class AtomicDouble extends Number } /** - * Creates a new AtomicDouble with initial value {@code 0.0}. + * Creates a new {@code AtomicDouble} with initial value {@code 0.0}. */ - public AtomicDouble() { this(0.0); } + public AtomicDouble() { + // assert doubleToRawLongBits(0.0) == 0L; + } /** * Gets the current value. @@ -81,17 +73,18 @@ public class AtomicDouble extends Number * @param newValue the new value */ public final void set(double newValue) { - value = doubleToRawLongBits(newValue); + long next = doubleToRawLongBits(newValue); + value = next; } /** * Eventually sets to the given value. * * @param newValue the new value - * @since 1.6 */ public final void lazySet(double newValue) { - unsafe.putOrderedLong(this, valueOffset, doubleToRawLongBits(newValue)); + long next = doubleToRawLongBits(newValue); + unsafe.putOrderedLong(this, valueOffset, next); } /** @@ -101,22 +94,23 @@ public class AtomicDouble extends Number * @return the previous value */ public final double getAndSet(double newValue) { - long newBits = doubleToRawLongBits(newValue); + long next = doubleToRawLongBits(newValue); while (true) { - long currentBits = value; - if (compareAndSet(currentBits, newBits)) - return longBitsToDouble(currentBits); + long current = value; + if (unsafe.compareAndSwapLong(this, valueOffset, current, next)) + return longBitsToDouble(current); } } /** * Atomically sets the value to the given updated value - * if the current value {@code ==} the expected value. + * if the current value is bitwise equal + * to the expected value. * * @param expect the expected value * @param update the new value - * @return true if successful. False return indicates that - * the actual value was not equal to the expected value. + * @return {@code true} if successful. False return indicates that + * the actual value was not bitwise equal to the expected value. */ public final boolean compareAndSet(double expect, double update) { return unsafe.compareAndSwapLong(this, valueOffset, @@ -126,15 +120,18 @@ public class AtomicDouble extends Number /** * Atomically sets the value to the given updated value - * if the current value {@code ==} the expected value. + * if the current value is bitwise equal + * to the expected value. * - *

May fail spuriously + *

May + * fail spuriously * and does not provide ordering guarantees, so is only rarely an * appropriate alternative to {@code compareAndSet}. * * @param expect the expected value * @param update the new value - * @return true if successful. + * @return {@code true} if successful */ public final boolean weakCompareAndSet(double expect, double update) { return compareAndSet(expect, update); @@ -148,10 +145,12 @@ public class AtomicDouble extends Number */ public final double getAndAdd(double delta) { while (true) { - long currentBits = value; - long nextBits = doubleToRawLongBits(longBitsToDouble(currentBits) + delta); - if (compareAndSet(currentBits, nextBits)) - return longBitsToDouble(currentBits); + long current = value; + double currentVal = longBitsToDouble(current); + double nextVal = currentVal + delta; + long next = doubleToRawLongBits(nextVal); + if (unsafe.compareAndSwapLong(this, valueOffset, current, next)) + return currentVal; } } @@ -162,52 +161,115 @@ public class AtomicDouble extends Number * @return the updated value */ public final double addAndGet(double delta) { - for (;;) { - double current = get(); - double next = current + delta; - if (compareAndSet(current, next)) - return next; + while (true) { + long current = value; + double currentVal = longBitsToDouble(current); + double nextVal = currentVal + delta; + long next = doubleToRawLongBits(nextVal); + if (unsafe.compareAndSwapLong(this, valueOffset, current, next)) + return nextVal; } } /** * Returns the String representation of the current value. - * @return the String representation of the current value. + * @return the String representation of the current value */ public String toString() { return Double.toString(get()); } - /** * Returns the value of this {@code AtomicDouble} as an {@code int} * after a narrowing primitive conversion. */ public int intValue() { - return (int)get(); + return (int) get(); } /** - * Returns the value of this {@code AtomicDouble} as a {@code long}. + * Returns the value of this {@code AtomicDouble} as a {@code long} + * after a narrowing primitive conversion. */ public long longValue() { - return (long)get(); + return (long) get(); } /** * Returns the value of this {@code AtomicDouble} as a {@code float} - * after a widening primitive conversion. + * after a narrowing primitive conversion. */ public float floatValue() { - return (float)get(); + return (float) get(); } /** - * Returns the value of this {@code AtomicDouble} as a {@code double} - * after a widening primitive conversion. + * Returns the value of this {@code AtomicDouble} as a {@code double}. */ public double doubleValue() { return get(); } + /** + * Saves the state to a stream (that is, serializes it). + * + * @serialData The current value is emitted (a {@code double}). + */ + private void writeObject(java.io.ObjectOutputStream s) + throws java.io.IOException { + s.defaultWriteObject(); + + s.writeDouble(get()); + } + + /** + * Reconstitutes the instance from a stream (that is, deserializes it). + */ + private void readObject(java.io.ObjectInputStream s) + throws java.io.IOException, ClassNotFoundException { + s.defaultReadObject(); + + set(s.readDouble()); + } + + // Unsafe mechanics + private static final sun.misc.Unsafe unsafe = getUnsafe(); + private static final long valueOffset; + + static { + try { + valueOffset = unsafe.objectFieldOffset + (AtomicDouble.class.getDeclaredField("value")); + } catch (Exception ex) { throw new Error(ex); } + } + + /** + * Returns a sun.misc.Unsafe. Suitable for use in a 3rd party package. + * Replace with a simple call to Unsafe.getUnsafe when integrating + * into a jdk. + * + * @return a sun.misc.Unsafe + */ + private static sun.misc.Unsafe getUnsafe() { + try { + return sun.misc.Unsafe.getUnsafe(); + } 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()); + } + } }