001 /*
002 * Written by Doug Lea with assistance from members of JCP JSR-166
003 * Expert Group and released to the public domain, as explained at
004 * http://creativecommons.org/publicdomain/zero/1.0/
005 */
006
007 /*
008 * Source:
009 * http://gee.cs.oswego.edu/cgi-bin/viewcvs.cgi/jsr166/src/jsr166e/extra/AtomicDoubleArray.java?revision=1.5
010 * (Modified to adapt to guava coding conventions and
011 * to use AtomicLongArray instead of sun.misc.Unsafe)
012 */
013
014 package com.google.common.util.concurrent;
015
016 import static java.lang.Double.doubleToRawLongBits;
017 import static java.lang.Double.longBitsToDouble;
018
019 import com.google.common.annotations.Beta;
020
021 import java.util.concurrent.atomic.AtomicLongArray;
022
023 /**
024 * A {@code double} array in which elements may be updated atomically.
025 * See the {@link java.util.concurrent.atomic} package specification
026 * for description of the properties of atomic variables.
027 *
028 * <p><a name="bitEquals">This class compares primitive {@code double}
029 * values in methods such as {@link #compareAndSet} by comparing their
030 * bitwise representation using {@link Double#doubleToRawLongBits},
031 * which differs from both the primitive double {@code ==} operator
032 * and from {@link Double#equals}, as if implemented by:
033 * <pre> {@code
034 * static boolean bitEquals(double x, double y) {
035 * long xBits = Double.doubleToRawLongBits(x);
036 * long yBits = Double.doubleToRawLongBits(y);
037 * return xBits == yBits;
038 * }}</pre>
039 *
040 * @author Doug Lea
041 * @author Martin Buchholz
042 * @since 11.0
043 */
044 @Beta
045 public class AtomicDoubleArray implements java.io.Serializable {
046 private static final long serialVersionUID = 0L;
047
048 // Making this non-final is the lesser evil according to Effective
049 // Java 2nd Edition Item 76: Write readObject methods defensively.
050 private transient AtomicLongArray longs;
051
052 /**
053 * Creates a new {@code AtomicDoubleArray} of the given length,
054 * with all elements initially zero.
055 *
056 * @param length the length of the array
057 */
058 public AtomicDoubleArray(int length) {
059 this.longs = new AtomicLongArray(length);
060 }
061
062 /**
063 * Creates a new {@code AtomicDoubleArray} with the same length
064 * as, and all elements copied from, the given array.
065 *
066 * @param array the array to copy elements from
067 * @throws NullPointerException if array is null
068 */
069 public AtomicDoubleArray(double[] array) {
070 final int len = array.length;
071 long[] longArray = new long[len];
072 for (int i = 0; i < len; i++) {
073 longArray[i] = doubleToRawLongBits(array[i]);
074 }
075 this.longs = new AtomicLongArray(longArray);
076 }
077
078 /**
079 * Returns the length of the array.
080 *
081 * @return the length of the array
082 */
083 public final int length() {
084 return longs.length();
085 }
086
087 /**
088 * Gets the current value at position {@code i}.
089 *
090 * @param i the index
091 * @return the current value
092 */
093 public final double get(int i) {
094 return longBitsToDouble(longs.get(i));
095 }
096
097 /**
098 * Sets the element at position {@code i} to the given value.
099 *
100 * @param i the index
101 * @param newValue the new value
102 */
103 public final void set(int i, double newValue) {
104 long next = doubleToRawLongBits(newValue);
105 longs.set(i, next);
106 }
107
108 /**
109 * Eventually sets the element at position {@code i} to the given value.
110 *
111 * @param i the index
112 * @param newValue the new value
113 */
114 public final void lazySet(int i, double newValue) {
115 set(i, newValue);
116 // TODO(user): replace with code below when jdk5 support is dropped.
117 // long next = doubleToRawLongBits(newValue);
118 // longs.lazySet(i, next);
119 }
120
121 /**
122 * Atomically sets the element at position {@code i} to the given value
123 * and returns the old value.
124 *
125 * @param i the index
126 * @param newValue the new value
127 * @return the previous value
128 */
129 public final double getAndSet(int i, double newValue) {
130 long next = doubleToRawLongBits(newValue);
131 return longBitsToDouble(longs.getAndSet(i, next));
132 }
133
134 /**
135 * Atomically sets the element at position {@code i} to the given
136 * updated value
137 * if the current value is <a href="#bitEquals">bitwise equal</a>
138 * to the expected value.
139 *
140 * @param i the index
141 * @param expect the expected value
142 * @param update the new value
143 * @return true if successful. False return indicates that
144 * the actual value was not equal to the expected value.
145 */
146 public final boolean compareAndSet(int i, double expect, double update) {
147 return longs.compareAndSet(i,
148 doubleToRawLongBits(expect),
149 doubleToRawLongBits(update));
150 }
151
152 /**
153 * Atomically sets the element at position {@code i} to the given
154 * updated value
155 * if the current value is <a href="#bitEquals">bitwise equal</a>
156 * to the expected value.
157 *
158 * <p>May <a
159 * href="http://download.oracle.com/javase/7/docs/api/java/util/concurrent/atomic/package-summary.html#Spurious">
160 * fail spuriously</a>
161 * and does not provide ordering guarantees, so is only rarely an
162 * appropriate alternative to {@code compareAndSet}.
163 *
164 * @param i the index
165 * @param expect the expected value
166 * @param update the new value
167 * @return true if successful
168 */
169 public final boolean weakCompareAndSet(int i, double expect, double update) {
170 return longs.weakCompareAndSet(i,
171 doubleToRawLongBits(expect),
172 doubleToRawLongBits(update));
173 }
174
175 /**
176 * Atomically adds the given value to the element at index {@code i}.
177 *
178 * @param i the index
179 * @param delta the value to add
180 * @return the previous value
181 */
182 public final double getAndAdd(int i, double delta) {
183 while (true) {
184 long current = longs.get(i);
185 double currentVal = longBitsToDouble(current);
186 double nextVal = currentVal + delta;
187 long next = doubleToRawLongBits(nextVal);
188 if (longs.compareAndSet(i, current, next)) {
189 return currentVal;
190 }
191 }
192 }
193
194 /**
195 * Atomically adds the given value to the element at index {@code i}.
196 *
197 * @param i the index
198 * @param delta the value to add
199 * @return the updated value
200 */
201 public double addAndGet(int i, double delta) {
202 while (true) {
203 long current = longs.get(i);
204 double currentVal = longBitsToDouble(current);
205 double nextVal = currentVal + delta;
206 long next = doubleToRawLongBits(nextVal);
207 if (longs.compareAndSet(i, current, next)) {
208 return nextVal;
209 }
210 }
211 }
212
213 /**
214 * Returns the String representation of the current values of array.
215 * @return the String representation of the current values of array
216 */
217 public String toString() {
218 int iMax = length() - 1;
219 if (iMax == -1) {
220 return "[]";
221 }
222
223 // Double.toString(Math.PI).length() == 17
224 StringBuilder b = new StringBuilder((17 + 2) * (iMax + 1));
225 b.append('[');
226 for (int i = 0;; i++) {
227 b.append(longBitsToDouble(longs.get(i)));
228 if (i == iMax) {
229 return b.append(']').toString();
230 }
231 b.append(',').append(' ');
232 }
233 }
234
235 /**
236 * Saves the state to a stream (that is, serializes it).
237 *
238 * @serialData The length of the array is emitted (int), followed by all
239 * of its elements (each a {@code double}) in the proper order.
240 */
241 private void writeObject(java.io.ObjectOutputStream s)
242 throws java.io.IOException {
243 s.defaultWriteObject();
244
245 // Write out array length
246 int length = length();
247 s.writeInt(length);
248
249 // Write out all elements in the proper order.
250 for (int i = 0; i < length; i++) {
251 s.writeDouble(get(i));
252 }
253 }
254
255 /**
256 * Reconstitutes the instance from a stream (that is, deserializes it).
257 */
258 private void readObject(java.io.ObjectInputStream s)
259 throws java.io.IOException, ClassNotFoundException {
260 s.defaultReadObject();
261
262 // Read in array length and allocate array
263 int length = s.readInt();
264 this.longs = new AtomicLongArray(length);
265
266 // Read in all elements in the proper order.
267 for (int i = 0; i < length; i++) {
268 set(i, s.readDouble());
269 }
270 }
271 }