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