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/*
9 * Source:
10 * http://gee.cs.oswego.edu/cgi-bin/viewcvs.cgi/jsr166/src/jsr166e/extra/AtomicDouble.java?revision=1.13
11 * (Modified to adapt to guava coding conventions and
12 * to use AtomicLongFieldUpdater instead of sun.misc.Unsafe)
13 */
14
15package com.google.common.util.concurrent;
16
17import com.google.common.annotations.Beta;
18
19import static java.lang.Double.doubleToRawLongBits;
20import static java.lang.Double.longBitsToDouble;
21import java.util.concurrent.atomic.AtomicLongFieldUpdater;
22
23/**
24 * A {@code double} value that may be updated atomically.  See the
25 * {@link java.util.concurrent.atomic} package specification for
26 * description of the properties of atomic variables.  An {@code
27 * AtomicDouble} is used in applications such as atomic accumulation,
28 * and cannot be used as a replacement for a {@link Double}.  However,
29 * this class does extend {@code Number} to allow uniform access by
30 * tools and utilities that deal with numerically-based classes.
31 *
32 * <p><a name="bitEquals">This class compares primitive {@code double}
33 * values in methods such as {@link #compareAndSet} by comparing their
34 * bitwise representation using {@link Double#doubleToRawLongBits},
35 * which differs from both the primitive double {@code ==} operator
36 * and from {@link Double#equals}, as if implemented by:
37 *  <pre> {@code
38 * static boolean bitEquals(double x, double y) {
39 *   long xBits = Double.doubleToRawLongBits(x);
40 *   long yBits = Double.doubleToRawLongBits(y);
41 *   return xBits == yBits;
42 * }}</pre>
43 *
44 * <p>It is possible to write a more scalable updater, at the cost of
45 * giving up strict atomicity.  See for example
46 * <a href="http://gee.cs.oswego.edu/dl/jsr166/dist/jsr166edocs/jsr166e/DoubleAdder.html"
47 * DoubleAdder>
48 * and
49 * <a href="http://gee.cs.oswego.edu/dl/jsr166/dist/jsr166edocs/jsr166e/DoubleMaxUpdater.html"
50 * DoubleMaxUpdater>.
51 *
52 * @author Doug Lea
53 * @author Martin Buchholz
54 * @since 11.0
55 */
56@Beta
57public class AtomicDouble extends Number implements java.io.Serializable {
58  private static final long serialVersionUID = 0L;
59
60  private transient volatile long value;
61
62  private static final AtomicLongFieldUpdater<AtomicDouble> updater =
63      AtomicLongFieldUpdater.newUpdater(AtomicDouble.class, "value");
64
65  /**
66   * Creates a new {@code AtomicDouble} with the given initial value.
67   *
68   * @param initialValue the initial value
69   */
70  public AtomicDouble(double initialValue) {
71    value = doubleToRawLongBits(initialValue);
72  }
73
74  /**
75   * Creates a new {@code AtomicDouble} with initial value {@code 0.0}.
76   */
77  public AtomicDouble() {
78    // assert doubleToRawLongBits(0.0) == 0L;
79  }
80
81  /**
82   * Gets the current value.
83   *
84   * @return the current value
85   */
86  public final double get() {
87    return longBitsToDouble(value);
88  }
89
90  /**
91   * Sets to the given value.
92   *
93   * @param newValue the new value
94   */
95  public final void set(double newValue) {
96    long next = doubleToRawLongBits(newValue);
97    value = next;
98  }
99
100  /**
101   * Eventually sets to the given value.
102   *
103   * @param newValue the new value
104   */
105  public final void lazySet(double newValue) {
106    set(newValue);
107    // TODO(user): replace with code below when jdk5 support is dropped.
108    // long next = doubleToRawLongBits(newValue);
109    // updater.lazySet(this, next);
110  }
111
112  /**
113   * Atomically sets to the given value and returns the old value.
114   *
115   * @param newValue the new value
116   * @return the previous value
117   */
118  public final double getAndSet(double newValue) {
119    long next = doubleToRawLongBits(newValue);
120    return longBitsToDouble(updater.getAndSet(this, next));
121  }
122
123  /**
124   * Atomically sets the value to the given updated value
125   * if the current value is <a href="#bitEquals">bitwise equal</a>
126   * to the expected value.
127   *
128   * @param expect the expected value
129   * @param update the new value
130   * @return {@code true} if successful. False return indicates that
131   * the actual value was not bitwise equal to the expected value.
132   */
133  public final boolean compareAndSet(double expect, double update) {
134    return updater.compareAndSet(this,
135                                 doubleToRawLongBits(expect),
136                                 doubleToRawLongBits(update));
137  }
138
139  /**
140   * Atomically sets the value to the given updated value
141   * if the current value is <a href="#bitEquals">bitwise equal</a>
142   * to the expected value.
143   *
144   * <p>May <a
145   * href="http://download.oracle.com/javase/7/docs/api/java/util/concurrent/atomic/package-summary.html#Spurious">
146   * fail spuriously</a>
147   * and does not provide ordering guarantees, so is only rarely an
148   * appropriate alternative to {@code compareAndSet}.
149   *
150   * @param expect the expected value
151   * @param update the new value
152   * @return {@code true} if successful
153   */
154  public final boolean weakCompareAndSet(double expect, double update) {
155    return updater.weakCompareAndSet(this,
156                                     doubleToRawLongBits(expect),
157                                     doubleToRawLongBits(update));
158  }
159
160  /**
161   * Atomically adds the given value to the current value.
162   *
163   * @param delta the value to add
164   * @return the previous value
165   */
166  public final double getAndAdd(double delta) {
167    while (true) {
168      long current = value;
169      double currentVal = longBitsToDouble(current);
170      double nextVal = currentVal + delta;
171      long next = doubleToRawLongBits(nextVal);
172      if (updater.compareAndSet(this, current, next)) {
173        return currentVal;
174      }
175    }
176  }
177
178  /**
179   * Atomically adds the given value to the current value.
180   *
181   * @param delta the value to add
182   * @return the updated value
183   */
184  public final double addAndGet(double delta) {
185    while (true) {
186      long current = value;
187      double currentVal = longBitsToDouble(current);
188      double nextVal = currentVal + delta;
189      long next = doubleToRawLongBits(nextVal);
190      if (updater.compareAndSet(this, current, next)) {
191        return nextVal;
192      }
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   * 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   * after a narrowing primitive conversion.
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 narrowing 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   */
231  public double doubleValue() {
232    return get();
233  }
234
235  /**
236   * Saves the state to a stream (that is, serializes it).
237   *
238   * @serialData The current value is emitted (a {@code double}).
239   */
240  private void writeObject(java.io.ObjectOutputStream s)
241      throws java.io.IOException {
242    s.defaultWriteObject();
243
244    s.writeDouble(get());
245  }
246
247  /**
248   * Reconstitutes the instance from a stream (that is, deserializes it).
249   */
250  private void readObject(java.io.ObjectInputStream s)
251      throws java.io.IOException, ClassNotFoundException {
252    s.defaultReadObject();
253
254    set(s.readDouble());
255  }
256}
257