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