ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/jsr166/jsr166/src/jsr166e/extra/AtomicDouble.java
Revision: 1.3
Committed: Tue Aug 9 08:28:54 2011 UTC (12 years, 10 months ago) by jsr166
Branch: MAIN
Changes since 1.2: +44 -15 lines
Log Message:
unsafe mechanics

File Contents

# User Rev Content
1 jsr166 1.1 /*
2 jsr166 1.2 * Written by Doug Lea and Martin Buchholz with assistance from
3     * members of JCP JSR-166 Expert Group and released to the public
4     * domain, as explained at
5 jsr166 1.1 * http://creativecommons.org/publicdomain/zero/1.0/
6     */
7    
8     package jsr166e.extra;
9     import static java.lang.Double.doubleToRawLongBits;
10     import static java.lang.Double.longBitsToDouble;
11    
12     /**
13     * A {@code double} value that may be updated atomically. See the
14     * {@link java.util.concurrent.atomic} package specification for
15 jsr166 1.2 * description of the properties of atomic variables. An {@code
16 jsr166 1.3 * AtomicDouble} is used in applications such as atomic accumulation,
17     * and cannot be used as a replacement for a {@link Double}. However,
18 jsr166 1.2 * this class does extend {@code Number} to allow uniform access by
19     * tools and utilities that deal with numerically-based classes.
20 jsr166 1.1 *
21 jsr166 1.2 * <p>This class differs from the primitive double {@code ==} operator
22     * and from {@link Double#equals} in that it uses purely bitwise
23     * equality in methods such as {@link #compareAndSet}, as if
24     * implemented by:
25     * <pre> {@code
26     * boolean bitEquals(double x, double y) {
27     * long xBits = Double.doubleToRawLongBits(x);
28     * long yBits = Double.doubleToRawLongBits(y);
29     * return xBits == yBits;
30     * }}</pre>
31 jsr166 1.3 *
32 jsr166 1.1 * @author Doug Lea
33 jsr166 1.2 * @author Martin Buchholz
34 jsr166 1.1 */
35     public class AtomicDouble extends Number implements java.io.Serializable {
36 jsr166 1.3 static final long serialVersionUID = -8405198993435143622L;
37 jsr166 1.1
38     // setup to use Unsafe.compareAndSwapLong for updates
39 jsr166 1.3 private static final sun.misc.Unsafe unsafe = getUnsafe();
40 jsr166 1.1 private static final long valueOffset;
41    
42     /**
43     * Records whether the underlying JVM supports lockless
44     * compareAndSwap for longs. While the Unsafe.compareAndSwapLong
45     * method works in either case, some constructions should be
46     * handled at Java level to avoid locking user-visible locks.
47     */
48     static final boolean VM_SUPPORTS_LONG_CAS = VMSupportsCS8();
49    
50     /**
51     * Returns whether underlying JVM supports lockless CompareAndSet
52     * for longs. Called only once and cached in VM_SUPPORTS_LONG_CAS.
53     */
54 jsr166 1.2 private static boolean VMSupportsCS8() {
55 jsr166 1.3 final Class<?> klazz = java.util.concurrent.atomic.AtomicLong.class;
56     return java.security.AccessController.doPrivileged
57     (new java.security.PrivilegedAction<Boolean>() {
58     public Boolean run() {
59     try {
60     java.lang.reflect.Method m =
61     klazz.getDeclaredMethod("VMSupportsCS8", new Class<?>[0]);
62     m.setAccessible(true);
63     return (Boolean) m.invoke(new Class<?>[0]);
64     } catch (Throwable t) { throw new Error(t); }
65     }});
66 jsr166 1.2 }
67 jsr166 1.1
68     static {
69     try {
70     valueOffset = unsafe.objectFieldOffset
71     (AtomicDouble.class.getDeclaredField("value"));
72     } catch (Exception ex) { throw new Error(ex); }
73     }
74    
75     private volatile long value;
76    
77     /**
78     * Creates a new AtomicDouble with the given initial value.
79     *
80     * @param initialValue the initial value
81     */
82     public AtomicDouble(double initialValue) {
83     value = doubleToRawLongBits(initialValue);
84     }
85    
86     /**
87     * Creates a new AtomicDouble with initial value {@code 0.0}.
88     */
89     public AtomicDouble() { this(0.0); }
90    
91     /**
92     * Gets the current value.
93     *
94     * @return the current value
95     */
96     public final double get() {
97     return longBitsToDouble(value);
98     }
99    
100     /**
101     * Sets to the given value.
102     *
103     * @param newValue the new value
104     */
105     public final void set(double newValue) {
106     value = doubleToRawLongBits(newValue);
107     }
108    
109     /**
110     * Eventually sets to the given value.
111     *
112     * @param newValue the new value
113     */
114     public final void lazySet(double newValue) {
115     unsafe.putOrderedLong(this, valueOffset, doubleToRawLongBits(newValue));
116     }
117    
118     /**
119     * Atomically sets to the given value and returns the old value.
120     *
121     * @param newValue the new value
122     * @return the previous value
123     */
124     public final double getAndSet(double newValue) {
125     long newBits = doubleToRawLongBits(newValue);
126     while (true) {
127     long currentBits = value;
128 jsr166 1.2 if (unsafe.compareAndSwapLong(this, valueOffset,
129     currentBits, newBits))
130 jsr166 1.1 return longBitsToDouble(currentBits);
131     }
132     }
133    
134     /**
135     * Atomically sets the value to the given updated value
136     * if the current value {@code ==} the expected value.
137     *
138     * @param expect the expected value
139     * @param update the new value
140     * @return true if successful. False return indicates that
141     * the actual value was not equal to the expected value.
142     */
143     public final boolean compareAndSet(double expect, double update) {
144     return unsafe.compareAndSwapLong(this, valueOffset,
145     doubleToRawLongBits(expect),
146     doubleToRawLongBits(update));
147     }
148    
149     /**
150     * Atomically sets the value to the given updated value
151     * if the current value {@code ==} the expected value.
152     *
153     * <p>May <a href="package-summary.html#Spurious">fail spuriously</a>
154     * and does not provide ordering guarantees, so is only rarely an
155     * appropriate alternative to {@code compareAndSet}.
156     *
157     * @param expect the expected value
158     * @param update the new value
159     * @return true if successful.
160     */
161     public final boolean weakCompareAndSet(double expect, double update) {
162     return compareAndSet(expect, update);
163     }
164    
165     /**
166     * Atomically adds the given value to the current value.
167     *
168     * @param delta the value to add
169     * @return the previous value
170     */
171     public final double getAndAdd(double delta) {
172     while (true) {
173     long currentBits = value;
174     long nextBits = doubleToRawLongBits(longBitsToDouble(currentBits) + delta);
175 jsr166 1.2 if (unsafe.compareAndSwapLong(this, valueOffset,
176     currentBits, nextBits))
177 jsr166 1.1 return longBitsToDouble(currentBits);
178     }
179     }
180    
181     /**
182     * Atomically adds the given value to the current value.
183     *
184     * @param delta the value to add
185     * @return the updated value
186     */
187     public final double addAndGet(double delta) {
188     for (;;) {
189     double current = get();
190     double next = current + delta;
191     if (compareAndSet(current, next))
192     return next;
193     }
194     }
195    
196     /**
197     * Returns the String representation of the current value.
198     * @return the String representation of the current value.
199     */
200     public String toString() {
201     return Double.toString(get());
202     }
203    
204    
205     /**
206     * Returns the value of this {@code AtomicDouble} as an {@code int}
207     * after a narrowing primitive conversion.
208     */
209     public int intValue() {
210     return (int)get();
211     }
212    
213     /**
214     * Returns the value of this {@code AtomicDouble} as a {@code long}.
215     */
216     public long longValue() {
217     return (long)get();
218     }
219    
220     /**
221     * Returns the value of this {@code AtomicDouble} as a {@code float}
222     * after a widening primitive conversion.
223     */
224     public float floatValue() {
225     return (float)get();
226     }
227    
228     /**
229     * Returns the value of this {@code AtomicDouble} as a {@code double}
230     * after a widening primitive conversion.
231     */
232     public double doubleValue() {
233     return get();
234     }
235    
236 jsr166 1.3 /**
237     * Returns a sun.misc.Unsafe. Suitable for use in a 3rd party package.
238     * Replace with a simple call to Unsafe.getUnsafe when integrating
239     * into a jdk.
240     *
241     * @return a sun.misc.Unsafe
242     */
243     private static sun.misc.Unsafe getUnsafe() {
244     try {
245     return sun.misc.Unsafe.getUnsafe();
246     } catch (SecurityException se) {
247     try {
248     return java.security.AccessController.doPrivileged
249     (new java.security
250     .PrivilegedExceptionAction<sun.misc.Unsafe>() {
251     public sun.misc.Unsafe run() throws Exception {
252     java.lang.reflect.Field f = sun.misc
253     .Unsafe.class.getDeclaredField("theUnsafe");
254     f.setAccessible(true);
255     return (sun.misc.Unsafe) f.get(null);
256     }});
257     } catch (java.security.PrivilegedActionException e) {
258     throw new RuntimeException("Could not initialize intrinsics",
259     e.getCause());
260     }
261     }
262     }
263    
264 jsr166 1.1 }