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 014package com.google.common.util.concurrent; 015 016import static com.google.common.base.Preconditions.checkNotNull; 017import static java.lang.Double.doubleToRawLongBits; 018import static java.lang.Double.longBitsToDouble; 019 020import com.google.common.annotations.GwtIncompatible; 021import com.google.common.annotations.J2ktIncompatible; 022import com.google.common.primitives.ImmutableLongArray; 023import com.google.errorprone.annotations.CanIgnoreReturnValue; 024import java.io.IOException; 025import java.io.ObjectInputStream; 026import java.io.ObjectOutputStream; 027import java.io.Serializable; 028import java.util.concurrent.atomic.AtomicLongArray; 029import java.util.function.DoubleBinaryOperator; 030import java.util.function.DoubleUnaryOperator; 031 032/** 033 * A {@code double} array in which elements may be updated atomically. See the {@link 034 * java.util.concurrent.atomic} package specification for description of the properties of atomic 035 * variables. 036 * 037 * <p><a id="bitEquals"></a>This class compares primitive {@code double} values in methods such as 038 * {@link #compareAndSet} by comparing their bitwise representation using {@link 039 * Double#doubleToRawLongBits}, which differs from both the primitive double {@code ==} operator and 040 * from {@link Double#equals}, as if implemented by: 041 * 042 * <pre>{@code 043 * static boolean bitEquals(double x, double y) { 044 * long xBits = Double.doubleToRawLongBits(x); 045 * long yBits = Double.doubleToRawLongBits(y); 046 * return xBits == yBits; 047 * } 048 * }</pre> 049 * 050 * @author Doug Lea 051 * @author Martin Buchholz 052 * @since 11.0 053 */ 054@GwtIncompatible 055@J2ktIncompatible 056@ElementTypesAreNonnullByDefault 057public class AtomicDoubleArray implements Serializable { 058 private static final long serialVersionUID = 0L; 059 060 // Making this non-final is the lesser evil according to Effective 061 // Java 2nd Edition Item 76: Write readObject methods defensively. 062 private transient AtomicLongArray longs; 063 064 /** 065 * Creates a new {@code AtomicDoubleArray} of the given length, with all elements initially zero. 066 * 067 * @param length the length of the array 068 */ 069 public AtomicDoubleArray(int length) { 070 this.longs = new AtomicLongArray(length); 071 } 072 073 /** 074 * Creates a new {@code AtomicDoubleArray} with the same length as, and all elements copied from, 075 * the given array. 076 * 077 * @param array the array to copy elements from 078 * @throws NullPointerException if array is null 079 */ 080 public AtomicDoubleArray(double[] array) { 081 int len = array.length; 082 long[] longArray = new long[len]; 083 for (int i = 0; i < len; i++) { 084 longArray[i] = doubleToRawLongBits(array[i]); 085 } 086 this.longs = new AtomicLongArray(longArray); 087 } 088 089 /** 090 * Returns the length of the array. 091 * 092 * @return the length of the array 093 */ 094 public final int length() { 095 return longs.length(); 096 } 097 098 /** 099 * Gets the current value at position {@code i}. 100 * 101 * @param i the index 102 * @return the current value 103 */ 104 public final double get(int i) { 105 return longBitsToDouble(longs.get(i)); 106 } 107 108 /** 109 * Atomically 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 set(int i, double newValue) { 115 long next = doubleToRawLongBits(newValue); 116 longs.set(i, next); 117 } 118 119 /** 120 * Eventually sets the element at position {@code i} to the given value. 121 * 122 * @param i the index 123 * @param newValue the new value 124 */ 125 public final void lazySet(int i, double newValue) { 126 long next = doubleToRawLongBits(newValue); 127 longs.lazySet(i, next); 128 } 129 130 /** 131 * Atomically sets the element at position {@code i} to the given value and returns the old value. 132 * 133 * @param i the index 134 * @param newValue the new value 135 * @return the previous value 136 */ 137 public final double getAndSet(int i, double newValue) { 138 long next = doubleToRawLongBits(newValue); 139 return longBitsToDouble(longs.getAndSet(i, next)); 140 } 141 142 /** 143 * Atomically sets the element at position {@code i} to the given updated value if the current 144 * value is <a href="#bitEquals">bitwise equal</a> to the expected value. 145 * 146 * @param i the index 147 * @param expect the expected value 148 * @param update the new value 149 * @return true if successful. False return indicates that the actual value was not equal to the 150 * expected value. 151 */ 152 public final boolean compareAndSet(int i, double expect, double update) { 153 return longs.compareAndSet(i, doubleToRawLongBits(expect), doubleToRawLongBits(update)); 154 } 155 156 /** 157 * Atomically sets the element at position {@code i} to the given updated value if the current 158 * value is <a href="#bitEquals">bitwise equal</a> to the expected value. 159 * 160 * <p>May <a 161 * href="http://download.oracle.com/javase/7/docs/api/java/util/concurrent/atomic/package-summary.html#Spurious"> 162 * fail spuriously</a> and does not provide ordering guarantees, so is only rarely an appropriate 163 * alternative to {@code compareAndSet}. 164 * 165 * @param i the index 166 * @param expect the expected value 167 * @param update the new value 168 * @return true if successful 169 */ 170 public final boolean weakCompareAndSet(int i, double expect, double update) { 171 return longs.weakCompareAndSet(i, doubleToRawLongBits(expect), doubleToRawLongBits(update)); 172 } 173 174 /** 175 * Atomically adds the given value to the element at index {@code i}. 176 * 177 * @param i the index 178 * @param delta the value to add 179 * @return the previous value 180 */ 181 @CanIgnoreReturnValue 182 public final double getAndAdd(int i, double delta) { 183 return getAndAccumulate(i, delta, Double::sum); 184 } 185 186 /** 187 * Atomically adds the given value to the element at index {@code i}. 188 * 189 * @param i the index 190 * @param delta the value to add 191 * @return the updated value 192 */ 193 @CanIgnoreReturnValue 194 public double addAndGet(int i, double delta) { 195 return accumulateAndGet(i, delta, Double::sum); 196 } 197 198 /** 199 * Atomically updates the element at index {@code i} with the results of applying the given 200 * function to the current and given values. 201 * 202 * @param i the index to update 203 * @param x the update value 204 * @param accumulatorFunction the accumulator function 205 * @return the previous value 206 * @since 31.1 207 */ 208 @CanIgnoreReturnValue 209 public final double getAndAccumulate(int i, double x, DoubleBinaryOperator accumulatorFunction) { 210 checkNotNull(accumulatorFunction); 211 return getAndUpdate(i, oldValue -> accumulatorFunction.applyAsDouble(oldValue, x)); 212 } 213 214 /** 215 * Atomically updates the element at index {@code i} with the results of applying the given 216 * function to the current and given values. 217 * 218 * @param i the index to update 219 * @param x the update value 220 * @param accumulatorFunction the accumulator function 221 * @return the updated value 222 * @since 31.1 223 */ 224 @CanIgnoreReturnValue 225 public final double accumulateAndGet(int i, double x, DoubleBinaryOperator accumulatorFunction) { 226 checkNotNull(accumulatorFunction); 227 return updateAndGet(i, oldValue -> accumulatorFunction.applyAsDouble(oldValue, x)); 228 } 229 230 /** 231 * Atomically updates the element at index {@code i} with the results of applying the given 232 * function to the current value. 233 * 234 * @param i the index to update 235 * @param updaterFunction the update function 236 * @return the previous value 237 * @since 31.1 238 */ 239 @CanIgnoreReturnValue 240 public final double getAndUpdate(int i, DoubleUnaryOperator updaterFunction) { 241 while (true) { 242 long current = longs.get(i); 243 double currentVal = longBitsToDouble(current); 244 double nextVal = updaterFunction.applyAsDouble(currentVal); 245 long next = doubleToRawLongBits(nextVal); 246 if (longs.compareAndSet(i, current, next)) { 247 return currentVal; 248 } 249 } 250 } 251 252 /** 253 * Atomically updates the element at index {@code i} with the results of applying the given 254 * function to the current value. 255 * 256 * @param i the index to update 257 * @param updaterFunction the update function 258 * @return the updated value 259 * @since 31.1 260 */ 261 @CanIgnoreReturnValue 262 public final double updateAndGet(int i, DoubleUnaryOperator updaterFunction) { 263 while (true) { 264 long current = longs.get(i); 265 double currentVal = longBitsToDouble(current); 266 double nextVal = updaterFunction.applyAsDouble(currentVal); 267 long next = doubleToRawLongBits(nextVal); 268 if (longs.compareAndSet(i, current, next)) { 269 return nextVal; 270 } 271 } 272 } 273 274 /** 275 * Returns the String representation of the current values of array. 276 * 277 * @return the String representation of the current values of array 278 */ 279 @Override 280 public String toString() { 281 int iMax = length() - 1; 282 if (iMax == -1) { 283 return "[]"; 284 } 285 286 // Double.toString(Math.PI).length() == 17 287 StringBuilder b = new StringBuilder((17 + 2) * (iMax + 1)); 288 b.append('['); 289 for (int i = 0; ; i++) { 290 b.append(longBitsToDouble(longs.get(i))); 291 if (i == iMax) { 292 return b.append(']').toString(); 293 } 294 b.append(',').append(' '); 295 } 296 } 297 298 /** 299 * Saves the state to a stream (that is, serializes it). 300 * 301 * @serialData The length of the array is emitted (int), followed by all of its elements (each a 302 * {@code double}) in the proper order. 303 */ 304 private void writeObject(ObjectOutputStream s) throws IOException { 305 s.defaultWriteObject(); 306 307 // Write out array length 308 int length = length(); 309 s.writeInt(length); 310 311 // Write out all elements in the proper order. 312 for (int i = 0; i < length; i++) { 313 s.writeDouble(get(i)); 314 } 315 } 316 317 /** Reconstitutes the instance from a stream (that is, deserializes it). */ 318 private void readObject(ObjectInputStream s) throws IOException, ClassNotFoundException { 319 s.defaultReadObject(); 320 321 int length = s.readInt(); 322 ImmutableLongArray.Builder builder = ImmutableLongArray.builder(); 323 for (int i = 0; i < length; i++) { 324 builder.add(doubleToRawLongBits(s.readDouble())); 325 } 326 this.longs = new AtomicLongArray(builder.build().toArray()); 327 } 328}