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