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, 055 * with all elements initially zero. 056 * 057 * @param length the length of the array 058 */ 059 public AtomicDoubleArray(int length) { 060 this.longs = new AtomicLongArray(length); 061 } 062 063 /** 064 * Creates a new {@code AtomicDoubleArray} with the same length 065 * as, and all elements copied from, the given array. 066 * 067 * @param array the array to copy elements from 068 * @throws NullPointerException if array is null 069 */ 070 public AtomicDoubleArray(double[] array) { 071 final int len = array.length; 072 long[] longArray = new long[len]; 073 for (int i = 0; i < len; i++) { 074 longArray[i] = doubleToRawLongBits(array[i]); 075 } 076 this.longs = new AtomicLongArray(longArray); 077 } 078 079 /** 080 * Returns the length of the array. 081 * 082 * @return the length of the array 083 */ 084 public final int length() { 085 return longs.length(); 086 } 087 088 /** 089 * Gets the current value at position {@code i}. 090 * 091 * @param i the index 092 * @return the current value 093 */ 094 public final double get(int i) { 095 return longBitsToDouble(longs.get(i)); 096 } 097 098 /** 099 * Sets the element at position {@code i} to the given value. 100 * 101 * @param i the index 102 * @param newValue the new value 103 */ 104 public final void set(int i, double newValue) { 105 long next = doubleToRawLongBits(newValue); 106 longs.set(i, next); 107 } 108 109 /** 110 * Eventually sets the element at position {@code i} to the given value. 111 * 112 * @param i the index 113 * @param newValue the new value 114 */ 115 public final void lazySet(int i, double newValue) { 116 set(i, newValue); 117 // TODO(user): replace with code below when jdk5 support is dropped. 118 // long next = doubleToRawLongBits(newValue); 119 // longs.lazySet(i, next); 120 } 121 122 /** 123 * Atomically sets the element at position {@code i} to the given value 124 * 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 137 * updated value 138 * if the current value is <a href="#bitEquals">bitwise equal</a> 139 * to the expected value. 140 * 141 * @param i the index 142 * @param expect the expected value 143 * @param update the new value 144 * @return true if successful. False return indicates that 145 * the actual value was not equal to the expected value. 146 */ 147 public final boolean compareAndSet(int i, double expect, double update) { 148 return longs.compareAndSet(i, 149 doubleToRawLongBits(expect), 150 doubleToRawLongBits(update)); 151 } 152 153 /** 154 * Atomically sets the element at position {@code i} to the given 155 * updated value 156 * if the current value is <a href="#bitEquals">bitwise equal</a> 157 * to the expected value. 158 * 159 * <p>May <a 160 * href="http://download.oracle.com/javase/7/docs/api/java/util/concurrent/atomic/package-summary.html#Spurious"> 161 * fail spuriously</a> 162 * and does not provide ordering guarantees, so is only rarely an 163 * appropriate alternative to {@code compareAndSet}. 164 * 165 * @param i the index 166 * @param expect the expected value 167 * @param update the new value 168 * @return true if successful 169 */ 170 public final boolean weakCompareAndSet(int i, double expect, double update) { 171 return longs.weakCompareAndSet(i, 172 doubleToRawLongBits(expect), 173 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 while (true) { 186 long current = longs.get(i); 187 double currentVal = longBitsToDouble(current); 188 double nextVal = currentVal + delta; 189 long next = doubleToRawLongBits(nextVal); 190 if (longs.compareAndSet(i, current, next)) { 191 return currentVal; 192 } 193 } 194 } 195 196 /** 197 * Atomically adds the given value to the element at index {@code i}. 198 * 199 * @param i the index 200 * @param delta the value to add 201 * @return the updated value 202 */ 203 @CanIgnoreReturnValue 204 public double addAndGet(int i, double delta) { 205 while (true) { 206 long current = longs.get(i); 207 double currentVal = longBitsToDouble(current); 208 double nextVal = currentVal + delta; 209 long next = doubleToRawLongBits(nextVal); 210 if (longs.compareAndSet(i, current, next)) { 211 return nextVal; 212 } 213 } 214 } 215 216 /** 217 * Returns the String representation of the current values of array. 218 * @return the String representation of the current values of array 219 */ 220 public String toString() { 221 int iMax = length() - 1; 222 if (iMax == -1) { 223 return "[]"; 224 } 225 226 // Double.toString(Math.PI).length() == 17 227 StringBuilder b = new StringBuilder((17 + 2) * (iMax + 1)); 228 b.append('['); 229 for (int i = 0;; i++) { 230 b.append(longBitsToDouble(longs.get(i))); 231 if (i == iMax) { 232 return b.append(']').toString(); 233 } 234 b.append(',').append(' '); 235 } 236 } 237 238 /** 239 * Saves the state to a stream (that is, serializes it). 240 * 241 * @serialData The length of the array is emitted (int), followed by all 242 * of its elements (each a {@code double}) in the proper order. 243 */ 244 private void writeObject(java.io.ObjectOutputStream s) 245 throws java.io.IOException { 246 s.defaultWriteObject(); 247 248 // Write out array length 249 int length = length(); 250 s.writeInt(length); 251 252 // Write out all elements in the proper order. 253 for (int i = 0; i < length; i++) { 254 s.writeDouble(get(i)); 255 } 256 } 257 258 /** 259 * Reconstitutes the instance from a stream (that is, deserializes it). 260 */ 261 private void readObject(java.io.ObjectInputStream s) 262 throws java.io.IOException, ClassNotFoundException { 263 s.defaultReadObject(); 264 265 // Read in array length and allocate array 266 int length = s.readInt(); 267 this.longs = new AtomicLongArray(length); 268 269 // Read in all elements in the proper order. 270 for (int i = 0; i < length; i++) { 271 set(i, s.readDouble()); 272 } 273 } 274}