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