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

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