1 /* 2 * Written by Doug Lea with assistance from members of JCP JSR-166 3 * Expert Group and released to the public domain, as explained at 4 * http://creativecommons.org/publicdomain/zero/1.0/ 5 */ 6 7 package java.util.concurrent.atomic; 8 9 import java.util.function.LongBinaryOperator; 10 import java.util.function.LongUnaryOperator; 11 12 /** 13 * A {@code long} array in which elements may be updated atomically. 14 * See the {@link java.util.concurrent.atomic} package specification 15 * for description of the properties of atomic variables. 16 * @since 1.5 17 * @author Doug Lea 18 */ 19 public class AtomicLongArray implements java.io.Serializable { 20 private static final long serialVersionUID = -2308431214976778248L; 21 22 private static final sun.misc.Unsafe U = sun.misc.Unsafe.getUnsafe(); 23 private static final int ABASE; 24 private static final int ASHIFT; 25 private final long[] array; 26 27 static { 28 ABASE = U.arrayBaseOffset(long[].class); 29 int scale = U.arrayIndexScale(long[].class); 30 if ((scale & (scale - 1)) != 0) 31 throw new Error("array index scale not a power of two"); 32 ASHIFT = 31 - Integer.numberOfLeadingZeros(scale); 33 } 34 checkedByteOffset(int i)35 private long checkedByteOffset(int i) { 36 if (i < 0 || i >= array.length) 37 throw new IndexOutOfBoundsException("index " + i); 38 39 return byteOffset(i); 40 } 41 byteOffset(int i)42 private static long byteOffset(int i) { 43 return ((long) i << ASHIFT) + ABASE; 44 } 45 46 /** 47 * Creates a new AtomicLongArray of the given length, with all 48 * elements initially zero. 49 * 50 * @param length the length of the array 51 */ AtomicLongArray(int length)52 public AtomicLongArray(int length) { 53 array = new long[length]; 54 } 55 56 /** 57 * Creates a new AtomicLongArray with the same length as, and 58 * all elements copied from, the given array. 59 * 60 * @param array the array to copy elements from 61 * @throws NullPointerException if array is null 62 */ AtomicLongArray(long[] array)63 public AtomicLongArray(long[] array) { 64 // Visibility guaranteed by final field guarantees 65 this.array = array.clone(); 66 } 67 68 /** 69 * Returns the length of the array. 70 * 71 * @return the length of the array 72 */ length()73 public final int length() { 74 return array.length; 75 } 76 77 /** 78 * Gets the current value at position {@code i}. 79 * 80 * @param i the index 81 * @return the current value 82 */ get(int i)83 public final long get(int i) { 84 return getRaw(checkedByteOffset(i)); 85 } 86 getRaw(long offset)87 private long getRaw(long offset) { 88 return U.getLongVolatile(array, offset); 89 } 90 91 /** 92 * Sets the element at position {@code i} to the given value. 93 * 94 * @param i the index 95 * @param newValue the new value 96 */ set(int i, long newValue)97 public final void set(int i, long newValue) { 98 U.putLongVolatile(array, checkedByteOffset(i), newValue); 99 } 100 101 /** 102 * Eventually sets the element at position {@code i} to the given value. 103 * 104 * @param i the index 105 * @param newValue the new value 106 * @since 1.6 107 */ lazySet(int i, long newValue)108 public final void lazySet(int i, long newValue) { 109 U.putOrderedLong(array, checkedByteOffset(i), newValue); 110 } 111 112 /** 113 * Atomically sets the element at position {@code i} to the given value 114 * and returns the old value. 115 * 116 * @param i the index 117 * @param newValue the new value 118 * @return the previous value 119 */ getAndSet(int i, long newValue)120 public final long getAndSet(int i, long newValue) { 121 return U.getAndSetLong(array, checkedByteOffset(i), newValue); 122 } 123 124 /** 125 * Atomically sets the element at position {@code i} to the given 126 * updated value if the current value {@code ==} the expected value. 127 * 128 * @param i the index 129 * @param expect the expected value 130 * @param update the new value 131 * @return {@code true} if successful. False return indicates that 132 * the actual value was not equal to the expected value. 133 */ compareAndSet(int i, long expect, long update)134 public final boolean compareAndSet(int i, long expect, long update) { 135 return compareAndSetRaw(checkedByteOffset(i), expect, update); 136 } 137 compareAndSetRaw(long offset, long expect, long update)138 private boolean compareAndSetRaw(long offset, long expect, long update) { 139 return U.compareAndSwapLong(array, offset, expect, update); 140 } 141 142 /** 143 * Atomically sets the element at position {@code i} to the given 144 * updated value if the current value {@code ==} the expected value. 145 * 146 * <p><a href="package-summary.html#weakCompareAndSet">May fail 147 * spuriously and does not provide ordering guarantees</a>, so is 148 * only rarely an appropriate alternative to {@code compareAndSet}. 149 * 150 * @param i the index 151 * @param expect the expected value 152 * @param update the new value 153 * @return {@code true} if successful 154 */ weakCompareAndSet(int i, long expect, long update)155 public final boolean weakCompareAndSet(int i, long expect, long update) { 156 return compareAndSet(i, expect, update); 157 } 158 159 /** 160 * Atomically increments by one the element at index {@code i}. 161 * 162 * @param i the index 163 * @return the previous value 164 */ getAndIncrement(int i)165 public final long getAndIncrement(int i) { 166 return getAndAdd(i, 1); 167 } 168 169 /** 170 * Atomically decrements by one the element at index {@code i}. 171 * 172 * @param i the index 173 * @return the previous value 174 */ getAndDecrement(int i)175 public final long getAndDecrement(int i) { 176 return getAndAdd(i, -1); 177 } 178 179 /** 180 * Atomically adds the given value to the element at index {@code i}. 181 * 182 * @param i the index 183 * @param delta the value to add 184 * @return the previous value 185 */ getAndAdd(int i, long delta)186 public final long getAndAdd(int i, long delta) { 187 return U.getAndAddLong(array, checkedByteOffset(i), delta); 188 } 189 190 /** 191 * Atomically increments by one the element at index {@code i}. 192 * 193 * @param i the index 194 * @return the updated value 195 */ incrementAndGet(int i)196 public final long incrementAndGet(int i) { 197 return getAndAdd(i, 1) + 1; 198 } 199 200 /** 201 * Atomically decrements by one the element at index {@code i}. 202 * 203 * @param i the index 204 * @return the updated value 205 */ decrementAndGet(int i)206 public final long decrementAndGet(int i) { 207 return getAndAdd(i, -1) - 1; 208 } 209 210 /** 211 * Atomically adds the given value to the element at index {@code i}. 212 * 213 * @param i the index 214 * @param delta the value to add 215 * @return the updated value 216 */ addAndGet(int i, long delta)217 public long addAndGet(int i, long delta) { 218 return getAndAdd(i, delta) + delta; 219 } 220 221 /** 222 * Atomically updates the element at index {@code i} with the results 223 * of applying the given function, returning the previous value. The 224 * function should be side-effect-free, since it may be re-applied 225 * when attempted updates fail due to contention among threads. 226 * 227 * @param i the index 228 * @param updateFunction a side-effect-free function 229 * @return the previous value 230 * @since 1.8 231 */ getAndUpdate(int i, LongUnaryOperator updateFunction)232 public final long getAndUpdate(int i, LongUnaryOperator updateFunction) { 233 long offset = checkedByteOffset(i); 234 long prev, next; 235 do { 236 prev = getRaw(offset); 237 next = updateFunction.applyAsLong(prev); 238 } while (!compareAndSetRaw(offset, prev, next)); 239 return prev; 240 } 241 242 /** 243 * Atomically updates the element at index {@code i} with the results 244 * of applying the given function, returning the updated value. The 245 * function should be side-effect-free, since it may be re-applied 246 * when attempted updates fail due to contention among threads. 247 * 248 * @param i the index 249 * @param updateFunction a side-effect-free function 250 * @return the updated value 251 * @since 1.8 252 */ updateAndGet(int i, LongUnaryOperator updateFunction)253 public final long updateAndGet(int i, LongUnaryOperator updateFunction) { 254 long offset = checkedByteOffset(i); 255 long prev, next; 256 do { 257 prev = getRaw(offset); 258 next = updateFunction.applyAsLong(prev); 259 } while (!compareAndSetRaw(offset, prev, next)); 260 return next; 261 } 262 263 /** 264 * Atomically updates the element at index {@code i} with the 265 * results of applying the given function to the current and 266 * given values, returning the previous value. The function should 267 * be side-effect-free, since it may be re-applied when attempted 268 * updates fail due to contention among threads. The function is 269 * applied with the current value at index {@code i} as its first 270 * argument, and the given update as the second argument. 271 * 272 * @param i the index 273 * @param x the update value 274 * @param accumulatorFunction a side-effect-free function of two arguments 275 * @return the previous value 276 * @since 1.8 277 */ getAndAccumulate(int i, long x, LongBinaryOperator accumulatorFunction)278 public final long getAndAccumulate(int i, long x, 279 LongBinaryOperator accumulatorFunction) { 280 long offset = checkedByteOffset(i); 281 long prev, next; 282 do { 283 prev = getRaw(offset); 284 next = accumulatorFunction.applyAsLong(prev, x); 285 } while (!compareAndSetRaw(offset, prev, next)); 286 return prev; 287 } 288 289 /** 290 * Atomically updates the element at index {@code i} with the 291 * results of applying the given function to the current and 292 * given values, returning the updated value. The function should 293 * be side-effect-free, since it may be re-applied when attempted 294 * updates fail due to contention among threads. The function is 295 * applied with the current value at index {@code i} as its first 296 * argument, and the given update as the second argument. 297 * 298 * @param i the index 299 * @param x the update value 300 * @param accumulatorFunction a side-effect-free function of two arguments 301 * @return the updated value 302 * @since 1.8 303 */ accumulateAndGet(int i, long x, LongBinaryOperator accumulatorFunction)304 public final long accumulateAndGet(int i, long x, 305 LongBinaryOperator accumulatorFunction) { 306 long offset = checkedByteOffset(i); 307 long prev, next; 308 do { 309 prev = getRaw(offset); 310 next = accumulatorFunction.applyAsLong(prev, x); 311 } while (!compareAndSetRaw(offset, prev, next)); 312 return next; 313 } 314 315 /** 316 * Returns the String representation of the current values of array. 317 * @return the String representation of the current values of array 318 */ toString()319 public String toString() { 320 int iMax = array.length - 1; 321 if (iMax == -1) 322 return "[]"; 323 324 StringBuilder b = new StringBuilder(); 325 b.append('['); 326 for (int i = 0; ; i++) { 327 b.append(getRaw(byteOffset(i))); 328 if (i == iMax) 329 return b.append(']').toString(); 330 b.append(',').append(' '); 331 } 332 } 333 334 } 335