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