Home | History | Annotate | Download | only in atomic
      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 
     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 
     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      */
     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      */
     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      */
    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      */
    112     public final long get(int i) {
    113         return getRaw(checkedByteOffset(i));
    114     }
    115 
    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      */
    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      */
    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      */
    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      */
    163     public final boolean compareAndSet(int i, long expect, long update) {
    164         return compareAndSetRaw(checkedByteOffset(i), expect, update);
    165     }
    166 
    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      */
    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      */
    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      */
    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      */
    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      */
    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      */
    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      */
    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      */
    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      */
    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      */
    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      */
    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      */
    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