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