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