--- jsr166/src/jsr166e/extra/AtomicDouble.java 2011/08/09 08:28:54 1.3 +++ jsr166/src/jsr166e/extra/AtomicDouble.java 2013/07/22 16:47:46 1.19 @@ -6,6 +6,7 @@ */ package jsr166e.extra; + import static java.lang.Double.doubleToRawLongBits; import static java.lang.Double.longBitsToDouble; @@ -18,64 +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; + private 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; + private transient volatile long value; /** - * 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 boolean VMSupportsCS8() { - final Class> klazz = java.util.concurrent.atomic.AtomicLong.class; - return java.security.AccessController.doPrivileged - (new java.security.PrivilegedAction
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 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);
@@ -170,11 +144,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;
}
}
@@ -185,55 +160,95 @@ 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).
+ *
+ * @param s the stream
+ * @throws java.io.IOException if an I/O error occurs
+ * @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).
+ * @param s the stream
+ * @throws ClassNotFoundException if the class of a serialized object
+ * could not be found
+ * @throws java.io.IOException if an I/O error occurs
+ */
+ 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.
@@ -243,22 +258,23 @@ public class AtomicDouble extends Number
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