--- jsr166/src/jsr166e/extra/AtomicDouble.java 2011/08/09 04:05:25 1.1 +++ jsr166/src/jsr166e/extra/AtomicDouble.java 2011/10/20 03:08:02 1.8 @@ -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
+ * 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;
-
- // 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();
-
- /**
- * 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 static final long serialVersionUID = -8405198993435143622L;
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,7 +52,7 @@ 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); }
@@ -81,17 +71,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 +92,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,7 +118,8 @@ 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
* and does not provide ordering guarantees, so is only rarely an
@@ -134,7 +127,7 @@ public class AtomicDouble extends Number
*
* @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 +141,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,23 +157,24 @@ 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.
@@ -188,7 +184,8 @@ public class AtomicDouble extends Number
}
/**
- * 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();
@@ -196,18 +193,55 @@ public class AtomicDouble extends Number
/**
* 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();
}
/**
- * 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();
}
+ // 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 se) {
+ try {
+ return java.security.AccessController.doPrivileged
+ (new java.security
+ .PrivilegedExceptionAction