Home | History | Annotate | Download | only in atomic
      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/licenses/publicdomain
      5  */
      6 
      7 package java.util.concurrent.atomic;
      8 import sun.misc.Unsafe;
      9 import java.util.*;
     10 
     11 /**
     12  * An {@code int} array in which elements may be updated atomically.
     13  * See the {@link java.util.concurrent.atomic} package
     14  * specification for description of the properties of atomic
     15  * variables.
     16  * @since 1.5
     17  * @author Doug Lea
     18  */
     19 public class AtomicIntegerArray implements java.io.Serializable {
     20     private static final long serialVersionUID = 2862133569453604235L;
     21 
     22     private static final Unsafe unsafe = UnsafeAccess.THE_ONE; // android-changed
     23     private static final int base = unsafe.arrayBaseOffset(int[].class);
     24     private static final int shift;
     25     private final int[] array;
     26 
     27     static {
     28         int scale = unsafe.arrayIndexScale(int[].class);
     29         if ((scale & (scale - 1)) != 0)
     30             throw new Error("data type scale not a power of two");
     31         shift = 31 - Integer.numberOfLeadingZeros(scale);
     32     }
     33 
     34     private long checkedByteOffset(int i) {
     35         if (i < 0 || i >= array.length)
     36             throw new IndexOutOfBoundsException("index " + i);
     37 
     38         return byteOffset(i);
     39     }
     40 
     41     private static long byteOffset(int i) {
     42         return ((long) i << shift) + base;
     43     }
     44 
     45     /**
     46      * Creates a new AtomicIntegerArray of the given length, with all
     47      * elements initially zero.
     48      *
     49      * @param length the length of the array
     50      */
     51     public AtomicIntegerArray(int length) {
     52         array = new int[length];
     53     }
     54 
     55     /**
     56      * Creates a new AtomicIntegerArray with the same length as, and
     57      * all elements copied from, the given array.
     58      *
     59      * @param array the array to copy elements from
     60      * @throws NullPointerException if array is null
     61      */
     62     public AtomicIntegerArray(int[] array) {
     63         // Visibility guaranteed by final field guarantees
     64         this.array = array.clone();
     65     }
     66 
     67     /**
     68      * Returns the length of the array.
     69      *
     70      * @return the length of the array
     71      */
     72     public final int length() {
     73         return array.length;
     74     }
     75 
     76     /**
     77      * Gets the current value at position {@code i}.
     78      *
     79      * @param i the index
     80      * @return the current value
     81      */
     82     public final int get(int i) {
     83         return getRaw(checkedByteOffset(i));
     84     }
     85 
     86     private int getRaw(long offset) {
     87         return unsafe.getIntVolatile(array, offset);
     88     }
     89 
     90     /**
     91      * Sets the element at position {@code i} to the given value.
     92      *
     93      * @param i the index
     94      * @param newValue the new value
     95      */
     96     public final void set(int i, int newValue) {
     97         unsafe.putIntVolatile(array, checkedByteOffset(i), newValue);
     98     }
     99 
    100     /**
    101      * Eventually sets the element at position {@code i} to the given value.
    102      *
    103      * @param i the index
    104      * @param newValue the new value
    105      * @since 1.6
    106      */
    107     public final void lazySet(int i, int newValue) {
    108         unsafe.putOrderedInt(array, checkedByteOffset(i), newValue);
    109     }
    110 
    111     /**
    112      * Atomically sets the element at position {@code i} to the given
    113      * value and returns the old value.
    114      *
    115      * @param i the index
    116      * @param newValue the new value
    117      * @return the previous value
    118      */
    119     public final int getAndSet(int i, int newValue) {
    120         long offset = checkedByteOffset(i);
    121         while (true) {
    122             int current = getRaw(offset);
    123             if (compareAndSetRaw(offset, current, newValue))
    124                 return current;
    125         }
    126     }
    127 
    128     /**
    129      * Atomically sets the element at position {@code i} to the given
    130      * updated value if the current value {@code ==} the expected value.
    131      *
    132      * @param i the index
    133      * @param expect the expected value
    134      * @param update the new value
    135      * @return true if successful. False return indicates that
    136      * the actual value was not equal to the expected value.
    137      */
    138     public final boolean compareAndSet(int i, int expect, int update) {
    139         return compareAndSetRaw(checkedByteOffset(i), expect, update);
    140     }
    141 
    142     private boolean compareAndSetRaw(long offset, int expect, int update) {
    143         return unsafe.compareAndSwapInt(array, offset, expect, update);
    144     }
    145 
    146     /**
    147      * Atomically sets the element at position {@code i} to the given
    148      * updated value if the current value {@code ==} the expected value.
    149      *
    150      * <p>May <a href="package-summary.html#Spurious">fail spuriously</a>
    151      * and does not provide ordering guarantees, so is only rarely an
    152      * appropriate alternative to {@code compareAndSet}.
    153      *
    154      * @param i the index
    155      * @param expect the expected value
    156      * @param update the new value
    157      * @return true if successful.
    158      */
    159     public final boolean weakCompareAndSet(int i, int expect, int update) {
    160         return compareAndSet(i, expect, update);
    161     }
    162 
    163     /**
    164      * Atomically increments by one the element at index {@code i}.
    165      *
    166      * @param i the index
    167      * @return the previous value
    168      */
    169     public final int getAndIncrement(int i) {
    170         return getAndAdd(i, 1);
    171     }
    172 
    173     /**
    174      * Atomically decrements by one the element at index {@code i}.
    175      *
    176      * @param i the index
    177      * @return the previous value
    178      */
    179     public final int getAndDecrement(int i) {
    180         return getAndAdd(i, -1);
    181     }
    182 
    183     /**
    184      * Atomically adds the given value to the element at index {@code i}.
    185      *
    186      * @param i the index
    187      * @param delta the value to add
    188      * @return the previous value
    189      */
    190     public final int getAndAdd(int i, int delta) {
    191         long offset = checkedByteOffset(i);
    192         while (true) {
    193             int current = getRaw(offset);
    194             if (compareAndSetRaw(offset, current, current + delta))
    195                 return current;
    196         }
    197     }
    198 
    199     /**
    200      * Atomically increments by one the element at index {@code i}.
    201      *
    202      * @param i the index
    203      * @return the updated value
    204      */
    205     public final int incrementAndGet(int i) {
    206         return addAndGet(i, 1);
    207     }
    208 
    209     /**
    210      * Atomically decrements by one the element at index {@code i}.
    211      *
    212      * @param i the index
    213      * @return the updated value
    214      */
    215     public final int decrementAndGet(int i) {
    216         return addAndGet(i, -1);
    217     }
    218 
    219     /**
    220      * Atomically adds the given value to the element at index {@code i}.
    221      *
    222      * @param i the index
    223      * @param delta the value to add
    224      * @return the updated value
    225      */
    226     public final int addAndGet(int i, int delta) {
    227         long offset = checkedByteOffset(i);
    228         while (true) {
    229             int current = getRaw(offset);
    230             int next = current + delta;
    231             if (compareAndSetRaw(offset, current, next))
    232                 return next;
    233         }
    234     }
    235 
    236     /**
    237      * Returns the String representation of the current values of array.
    238      * @return the String representation of the current values of array
    239      */
    240     public String toString() {
    241         int iMax = array.length - 1;
    242         if (iMax == -1)
    243             return "[]";
    244 
    245         StringBuilder b = new StringBuilder();
    246         b.append('[');
    247         for (int i = 0; ; i++) {
    248             b.append(getRaw(byteOffset(i)));
    249             if (i == iMax)
    250                 return b.append(']').toString();
    251             b.append(',').append(' ');
    252         }
    253     }
    254 
    255 }
    256