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