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