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/licenses/publicdomain 5 */ 6 7 package java.util.concurrent.atomic; 8 import sun.misc.Unsafe; 9 import java.util.*; 10 11 /** 12 * An {@code int} array in which elements may be updated atomically. 13 * See the {@link java.util.concurrent.atomic} package 14 * specification for description of the properties of atomic 15 * variables. 16 * @since 1.5 17 * @author Doug Lea 18 */ 19 public class AtomicIntegerArray implements java.io.Serializable { 20 private static final long serialVersionUID = 2862133569453604235L; 21 22 private static final Unsafe unsafe = UnsafeAccess.THE_ONE; // android-changed 23 private static final int base = unsafe.arrayBaseOffset(int[].class); 24 private static final int shift; 25 private final int[] array; 26 27 static { 28 int scale = unsafe.arrayIndexScale(int[].class); 29 if ((scale & (scale - 1)) != 0) 30 throw new Error("data type scale not a power of two"); 31 shift = 31 - Integer.numberOfLeadingZeros(scale); 32 } 33 34 private long checkedByteOffset(int i) { 35 if (i < 0 || i >= array.length) 36 throw new IndexOutOfBoundsException("index " + i); 37 38 return byteOffset(i); 39 } 40 41 private static long byteOffset(int i) { 42 return ((long) i << shift) + base; 43 } 44 45 /** 46 * Creates a new AtomicIntegerArray of the given length, with all 47 * elements initially zero. 48 * 49 * @param length the length of the array 50 */ 51 public AtomicIntegerArray(int length) { 52 array = new int[length]; 53 } 54 55 /** 56 * Creates a new AtomicIntegerArray with the same length as, and 57 * all elements copied from, the given array. 58 * 59 * @param array the array to copy elements from 60 * @throws NullPointerException if array is null 61 */ 62 public AtomicIntegerArray(int[] array) { 63 // Visibility guaranteed by final field guarantees 64 this.array = array.clone(); 65 } 66 67 /** 68 * Returns the length of the array. 69 * 70 * @return the length of the array 71 */ 72 public final int length() { 73 return array.length; 74 } 75 76 /** 77 * Gets the current value at position {@code i}. 78 * 79 * @param i the index 80 * @return the current value 81 */ 82 public final int get(int i) { 83 return getRaw(checkedByteOffset(i)); 84 } 85 86 private int getRaw(long offset) { 87 return unsafe.getIntVolatile(array, offset); 88 } 89 90 /** 91 * Sets the element at position {@code i} to the given value. 92 * 93 * @param i the index 94 * @param newValue the new value 95 */ 96 public final void set(int i, int newValue) { 97 unsafe.putIntVolatile(array, checkedByteOffset(i), newValue); 98 } 99 100 /** 101 * Eventually sets the element at position {@code i} to the given value. 102 * 103 * @param i the index 104 * @param newValue the new value 105 * @since 1.6 106 */ 107 public final void lazySet(int i, int newValue) { 108 unsafe.putOrderedInt(array, checkedByteOffset(i), newValue); 109 } 110 111 /** 112 * Atomically sets the element at position {@code i} to the given 113 * value and returns the old value. 114 * 115 * @param i the index 116 * @param newValue the new value 117 * @return the previous value 118 */ 119 public final int getAndSet(int i, int newValue) { 120 long offset = checkedByteOffset(i); 121 while (true) { 122 int current = getRaw(offset); 123 if (compareAndSetRaw(offset, current, newValue)) 124 return current; 125 } 126 } 127 128 /** 129 * Atomically sets the element at position {@code i} to the given 130 * updated value if the current value {@code ==} the expected value. 131 * 132 * @param i the index 133 * @param expect the expected value 134 * @param update the new value 135 * @return true if successful. False return indicates that 136 * the actual value was not equal to the expected value. 137 */ 138 public final boolean compareAndSet(int i, int expect, int update) { 139 return compareAndSetRaw(checkedByteOffset(i), expect, update); 140 } 141 142 private boolean compareAndSetRaw(long offset, int expect, int update) { 143 return unsafe.compareAndSwapInt(array, offset, expect, update); 144 } 145 146 /** 147 * Atomically sets the element at position {@code i} to the given 148 * updated value if the current value {@code ==} the expected value. 149 * 150 * <p>May <a href="package-summary.html#Spurious">fail spuriously</a> 151 * and does not provide ordering guarantees, so is only rarely an 152 * appropriate 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, int expect, int update) { 160 return compareAndSet(i, expect, update); 161 } 162 163 /** 164 * Atomically increments by one the element at index {@code i}. 165 * 166 * @param i the index 167 * @return the previous value 168 */ 169 public final int getAndIncrement(int i) { 170 return getAndAdd(i, 1); 171 } 172 173 /** 174 * Atomically decrements by one the element at index {@code i}. 175 * 176 * @param i the index 177 * @return the previous value 178 */ 179 public final int getAndDecrement(int i) { 180 return getAndAdd(i, -1); 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 previous value 189 */ 190 public final int getAndAdd(int i, int delta) { 191 long offset = checkedByteOffset(i); 192 while (true) { 193 int current = getRaw(offset); 194 if (compareAndSetRaw(offset, current, current + delta)) 195 return current; 196 } 197 } 198 199 /** 200 * Atomically increments by one the element at index {@code i}. 201 * 202 * @param i the index 203 * @return the updated value 204 */ 205 public final int incrementAndGet(int i) { 206 return addAndGet(i, 1); 207 } 208 209 /** 210 * Atomically decrements by one the element at index {@code i}. 211 * 212 * @param i the index 213 * @return the updated value 214 */ 215 public final int decrementAndGet(int i) { 216 return addAndGet(i, -1); 217 } 218 219 /** 220 * Atomically adds the given value to the element at index {@code i}. 221 * 222 * @param i the index 223 * @param delta the value to add 224 * @return the updated value 225 */ 226 public final int addAndGet(int i, int delta) { 227 long offset = checkedByteOffset(i); 228 while (true) { 229 int current = getRaw(offset); 230 int next = current + delta; 231 if (compareAndSetRaw(offset, current, next)) 232 return next; 233 } 234 } 235 236 /** 237 * Returns the String representation of the current values of array. 238 * @return the String representation of the current values of array 239 */ 240 public String toString() { 241 int iMax = array.length - 1; 242 if (iMax == -1) 243 return "[]"; 244 245 StringBuilder b = new StringBuilder(); 246 b.append('['); 247 for (int i = 0; ; i++) { 248 b.append(getRaw(byteOffset(i))); 249 if (i == iMax) 250 return b.append(']').toString(); 251 b.append(',').append(' '); 252 } 253 } 254 255 } 256