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