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

# Content
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 * 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 * description of the properties of atomic variables. An {@code
16 * AtomicDouble} is used in applications such as atomic accumulation,
17 * and cannot be used as a replacement for a {@link Double}. However,
18 * this class does extend {@code Number} to allow uniform access by
19 * tools and utilities that deal with numerically-based classes.
20 *
21 * <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 *
32 * @author Doug Lea
33 * @author Martin Buchholz
34 */
35 public class AtomicDouble extends Number implements java.io.Serializable {
36 static final long serialVersionUID = -8405198993435143622L;
37
38 // setup to use Unsafe.compareAndSwapLong for updates
39 private static final sun.misc.Unsafe unsafe = getUnsafe();
40 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 private static boolean VMSupportsCS8() {
55 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 }
67
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 if (unsafe.compareAndSwapLong(this, valueOffset,
129 currentBits, newBits))
130 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 if (unsafe.compareAndSwapLong(this, valueOffset,
176 currentBits, nextBits))
177 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 /**
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 }