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