--- jsr166/src/jsr166e/extra/AtomicDouble.java 2011/08/09 19:10:29 1.4 +++ jsr166/src/jsr166e/extra/AtomicDouble.java 2011/10/25 19:21:27 1.11 @@ -6,6 +6,7 @@ */ package jsr166e.extra; + import static java.lang.Double.doubleToRawLongBits; import static java.lang.Double.longBitsToDouble; @@ -18,38 +19,31 @@ import static java.lang.Double.longBitsT * this class does extend {@code Number} to allow uniform access by * tools and utilities that deal with numerically-based classes. * - *
This class differs from the primitive double {@code ==} operator - * and from {@link Double#equals} in that it uses purely bitwise - * equality in methods such as {@link #compareAndSet}, as if - * implemented by: + *
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;
* }}
*
+ * @see jsr166e.DoubleAdder
+ * @see jsr166e.DoubleMaxUpdater
+ *
* @author Doug Lea
* @author Martin Buchholz
*/
public class AtomicDouble extends Number implements java.io.Serializable {
- static final long serialVersionUID = -8405198993435143622L;
-
- // setup to use Unsafe.compareAndSwapLong for updates
- 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); }
- }
+ private static final long serialVersionUID = -8405198993435143622L;
- private volatile long value;
+ private volatile transient 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
*/
@@ -58,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.
@@ -77,7 +73,8 @@ 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;
}
/**
@@ -86,7 +83,8 @@ public class AtomicDouble extends Number
* @param newValue the new value
*/
public final void lazySet(double newValue) {
- unsafe.putOrderedLong(this, valueOffset, doubleToRawLongBits(newValue));
+ long next = doubleToRawLongBits(newValue);
+ unsafe.putOrderedLong(this, valueOffset, next);
}
/**
@@ -96,23 +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 (unsafe.compareAndSwapLong(this, valueOffset,
- 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,
@@ -122,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); @@ -144,11 +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 (unsafe.compareAndSwapLong(this, valueOffset, - 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; } } @@ -159,55 +161,89 @@ 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. @@ -234,5 +270,4 @@ public class AtomicDouble extends Number } } } - }