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.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 
     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 
     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      */
     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      */
     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      */
    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      */
    113     public final int get(int i) {
    114         return getRaw(checkedByteOffset(i));
    115     }
    116 
    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      */
    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      */
    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      */
    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      */
    164     public final boolean compareAndSet(int i, int expect, int update) {
    165         return compareAndSetRaw(checkedByteOffset(i), expect, update);
    166     }
    167 
    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      */
    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      */
    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      */
    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      */
    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      */
    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      */
    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      */
    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      */
    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      */
    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      */
    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      */
    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      */
    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