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