1 /* 2 * Written by Doug Lea with assistance from members of JCP JSR-166 3 * Expert Group and released to the public domain, as explained at 4 * http://creativecommons.org/publicdomain/zero/1.0/ 5 */ 6 7 /* 8 * Source: 9 * http://gee.cs.oswego.edu/cgi-bin/viewcvs.cgi/jsr166/src/jsr166e/extra/AtomicDoubleArray.java?revision=1.5 10 * (Modified to adapt to guava coding conventions and 11 * to use AtomicLongArray instead of sun.misc.Unsafe) 12 */ 13 14 package com.google.common.util.concurrent; 15 16 import static java.lang.Double.doubleToRawLongBits; 17 import static java.lang.Double.longBitsToDouble; 18 19 import java.util.concurrent.atomic.AtomicLongArray; 20 21 /** 22 * A {@code double} array in which elements may be updated atomically. 23 * See the {@link java.util.concurrent.atomic} package specification 24 * for description of the properties of atomic variables. 25 * 26 * <p><a name="bitEquals">This class compares primitive {@code double} 27 * values in methods such as {@link #compareAndSet} by comparing their 28 * bitwise representation using {@link Double#doubleToRawLongBits}, 29 * which differs from both the primitive double {@code ==} operator 30 * and from {@link Double#equals}, as if implemented by: 31 * <pre> {@code 32 * static boolean bitEquals(double x, double y) { 33 * long xBits = Double.doubleToRawLongBits(x); 34 * long yBits = Double.doubleToRawLongBits(y); 35 * return xBits == yBits; 36 * }}</pre> 37 * 38 * @author Doug Lea 39 * @author Martin Buchholz 40 * @since 11.0 41 */ 42 public class AtomicDoubleArray implements java.io.Serializable { 43 private static final long serialVersionUID = 0L; 44 45 // Making this non-final is the lesser evil according to Effective 46 // Java 2nd Edition Item 76: Write readObject methods defensively. 47 private transient AtomicLongArray longs; 48 49 /** 50 * Creates a new {@code AtomicDoubleArray} of the given length, 51 * with all elements initially zero. 52 * 53 * @param length the length of the array 54 */ AtomicDoubleArray(int length)55 public AtomicDoubleArray(int length) { 56 this.longs = new AtomicLongArray(length); 57 } 58 59 /** 60 * Creates a new {@code AtomicDoubleArray} with the same length 61 * as, and all elements copied from, the given array. 62 * 63 * @param array the array to copy elements from 64 * @throws NullPointerException if array is null 65 */ AtomicDoubleArray(double[] array)66 public AtomicDoubleArray(double[] array) { 67 final int len = array.length; 68 long[] longArray = new long[len]; 69 for (int i = 0; i < len; i++) { 70 longArray[i] = doubleToRawLongBits(array[i]); 71 } 72 this.longs = new AtomicLongArray(longArray); 73 } 74 75 /** 76 * Returns the length of the array. 77 * 78 * @return the length of the array 79 */ length()80 public final int length() { 81 return longs.length(); 82 } 83 84 /** 85 * Gets the current value at position {@code i}. 86 * 87 * @param i the index 88 * @return the current value 89 */ get(int i)90 public final double get(int i) { 91 return longBitsToDouble(longs.get(i)); 92 } 93 94 /** 95 * Sets the element at position {@code i} to the given value. 96 * 97 * @param i the index 98 * @param newValue the new value 99 */ set(int i, double newValue)100 public final void set(int i, double newValue) { 101 long next = doubleToRawLongBits(newValue); 102 longs.set(i, next); 103 } 104 105 /** 106 * Eventually sets the element at position {@code i} to the given value. 107 * 108 * @param i the index 109 * @param newValue the new value 110 */ lazySet(int i, double newValue)111 public final void lazySet(int i, double newValue) { 112 set(i, newValue); 113 // TODO(user): replace with code below when jdk5 support is dropped. 114 // long next = doubleToRawLongBits(newValue); 115 // longs.lazySet(i, next); 116 } 117 118 /** 119 * Atomically sets the element at position {@code i} to the given value 120 * and returns the old value. 121 * 122 * @param i the index 123 * @param newValue the new value 124 * @return the previous value 125 */ getAndSet(int i, double newValue)126 public final double getAndSet(int i, double newValue) { 127 long next = doubleToRawLongBits(newValue); 128 return longBitsToDouble(longs.getAndSet(i, next)); 129 } 130 131 /** 132 * Atomically sets the element at position {@code i} to the given 133 * updated value 134 * if the current value is <a href="#bitEquals">bitwise equal</a> 135 * to the expected value. 136 * 137 * @param i the index 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 */ compareAndSet(int i, double expect, double update)143 public final boolean compareAndSet(int i, double expect, double update) { 144 return longs.compareAndSet(i, 145 doubleToRawLongBits(expect), 146 doubleToRawLongBits(update)); 147 } 148 149 /** 150 * Atomically sets the element at position {@code i} to the given 151 * updated value 152 * if the current value is <a href="#bitEquals">bitwise equal</a> 153 * to the expected value. 154 * 155 * <p>May <a 156 * href="http://download.oracle.com/javase/7/docs/api/java/util/concurrent/atomic/package-summary.html#Spurious"> 157 * fail spuriously</a> 158 * and does not provide ordering guarantees, so is only rarely an 159 * appropriate alternative to {@code compareAndSet}. 160 * 161 * @param i the index 162 * @param expect the expected value 163 * @param update the new value 164 * @return true if successful 165 */ weakCompareAndSet(int i, double expect, double update)166 public final boolean weakCompareAndSet(int i, double expect, double update) { 167 return longs.weakCompareAndSet(i, 168 doubleToRawLongBits(expect), 169 doubleToRawLongBits(update)); 170 } 171 172 /** 173 * Atomically adds the given value to the element at index {@code i}. 174 * 175 * @param i the index 176 * @param delta the value to add 177 * @return the previous value 178 */ getAndAdd(int i, double delta)179 public final double getAndAdd(int i, double delta) { 180 while (true) { 181 long current = longs.get(i); 182 double currentVal = longBitsToDouble(current); 183 double nextVal = currentVal + delta; 184 long next = doubleToRawLongBits(nextVal); 185 if (longs.compareAndSet(i, current, next)) { 186 return currentVal; 187 } 188 } 189 } 190 191 /** 192 * Atomically adds the given value to the element at index {@code i}. 193 * 194 * @param i the index 195 * @param delta the value to add 196 * @return the updated value 197 */ addAndGet(int i, double delta)198 public double addAndGet(int i, double delta) { 199 while (true) { 200 long current = longs.get(i); 201 double currentVal = longBitsToDouble(current); 202 double nextVal = currentVal + delta; 203 long next = doubleToRawLongBits(nextVal); 204 if (longs.compareAndSet(i, current, next)) { 205 return nextVal; 206 } 207 } 208 } 209 210 /** 211 * Returns the String representation of the current values of array. 212 * @return the String representation of the current values of array 213 */ toString()214 public String toString() { 215 int iMax = length() - 1; 216 if (iMax == -1) { 217 return "[]"; 218 } 219 220 // Double.toString(Math.PI).length() == 17 221 StringBuilder b = new StringBuilder((17 + 2) * (iMax + 1)); 222 b.append('['); 223 for (int i = 0;; i++) { 224 b.append(longBitsToDouble(longs.get(i))); 225 if (i == iMax) { 226 return b.append(']').toString(); 227 } 228 b.append(',').append(' '); 229 } 230 } 231 232 /** 233 * Saves the state to a stream (that is, serializes it). 234 * 235 * @serialData The length of the array is emitted (int), followed by all 236 * of its elements (each a {@code double}) in the proper order. 237 */ writeObject(java.io.ObjectOutputStream s)238 private void writeObject(java.io.ObjectOutputStream s) 239 throws java.io.IOException { 240 s.defaultWriteObject(); 241 242 // Write out array length 243 int length = length(); 244 s.writeInt(length); 245 246 // Write out all elements in the proper order. 247 for (int i = 0; i < length; i++) { 248 s.writeDouble(get(i)); 249 } 250 } 251 252 /** 253 * Reconstitutes the instance from a stream (that is, deserializes it). 254 */ readObject(java.io.ObjectInputStream s)255 private void readObject(java.io.ObjectInputStream s) 256 throws java.io.IOException, ClassNotFoundException { 257 s.defaultReadObject(); 258 259 // Read in array length and allocate array 260 int length = s.readInt(); 261 this.longs = new AtomicLongArray(length); 262 263 // Read in all elements in the proper order. 264 for (int i = 0; i < length; i++) { 265 set(i, s.readDouble()); 266 } 267 } 268 } 269