--- jsr166/src/jsr166e/extra/AtomicDouble.java 2011/08/09 04:05:25 1.1 +++ jsr166/src/jsr166e/extra/AtomicDouble.java 2011/08/09 19:10:29 1.4 @@ -1,48 +1,44 @@ /* - * 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 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: + *

 {@code
+ * boolean bitEquals(double x, double y) {
+ *   long xBits = Double.doubleToRawLongBits(x);
+ *   long yBits = Double.doubleToRawLongBits(y);
+ *   return xBits == yBits;
+ * }}
* - * @since 1.5 * @author Doug Lea + * @author Martin Buchholz */ public class AtomicDouble extends Number implements java.io.Serializable { - private static final long serialVersionUID = 1927816293512124184L; + static final long serialVersionUID = -8405198993435143622L; // setup to use Unsafe.compareAndSwapLong for updates - private static final Unsafe unsafe = Unsafe.getUnsafe(); + private static final sun.misc.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 @@ -88,7 +84,6 @@ public class AtomicDouble extends Number * 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)); @@ -104,7 +99,8 @@ public class AtomicDouble extends Number long newBits = doubleToRawLongBits(newValue); while (true) { long currentBits = value; - if (compareAndSet(currentBits, newBits)) + if (unsafe.compareAndSwapLong(this, valueOffset, + currentBits, newBits)) return longBitsToDouble(currentBits); } } @@ -150,7 +146,8 @@ public class AtomicDouble extends Number while (true) { long currentBits = value; long nextBits = doubleToRawLongBits(longBitsToDouble(currentBits) + delta); - if (compareAndSet(currentBits, nextBits)) + if (unsafe.compareAndSwapLong(this, valueOffset, + currentBits, nextBits)) return longBitsToDouble(currentBits); } } @@ -210,4 +207,32 @@ public class AtomicDouble extends Number return get(); } + /** + * 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() { + 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()); + } + } + } + }