Source for java.util.concurrent.atomic.AtomicReferenceArray

   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 array of object references in which elements may be updated
  13:  * atomically.  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:  * @param <E> The base class of elements held in this array
  19:  */
  20: public class AtomicReferenceArray<E> implements java.io.Serializable {
  21:     private static final long serialVersionUID = -6209656149925076980L;
  22: 
  23:     private static final Unsafe unsafe = Unsafe.getUnsafe();
  24:     private static final int base = unsafe.arrayBaseOffset(Object[].class);
  25:     private static final int scale = unsafe.arrayIndexScale(Object[].class);
  26:     private final Object[] array;
  27: 
  28:     private long rawIndex(int i) {
  29:         if (i < 0 || i >= array.length)
  30:             throw new IndexOutOfBoundsException("index " + i);
  31:         return base + i * scale;
  32:     }
  33: 
  34:     /**
  35:      * Creates a new AtomicReferenceArray of given length.
  36:      * @param length the length of the array
  37:      */
  38:     public AtomicReferenceArray(int length) {
  39:         array = new Object[length];
  40:         // must perform at least one volatile write to conform to JMM
  41:         if (length > 0)
  42:             unsafe.putObjectVolatile(array, rawIndex(0), null);
  43:     }
  44: 
  45:     /**
  46:      * Creates a new AtomicReferenceArray with the same length as, and
  47:      * all elements copied from, the given array.
  48:      *
  49:      * @param array the array to copy elements from
  50:      * @throws NullPointerException if array is null
  51:      */
  52:     public AtomicReferenceArray(E[] array) {
  53:         if (array == null)
  54:             throw new NullPointerException();
  55:         int length = array.length;
  56:         this.array = new Object[length];
  57:         if (length > 0) {
  58:             int last = length-1;
  59:             for (int i = 0; i < last; ++i)
  60:                 this.array[i] = array[i];
  61:             // Do the last write as volatile
  62:             E e = array[last];
  63:             unsafe.putObjectVolatile(this.array, rawIndex(last), e);
  64:         }
  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 <tt>i</tt>.
  78:      *
  79:      * @param i the index
  80:      * @return the current value
  81:      */
  82:     public final E get(int i) {
  83:         return (E) unsafe.getObjectVolatile(array, rawIndex(i));
  84:     }
  85: 
  86:     /**
  87:      * Sets the element at position <tt>i</tt> to the given value.
  88:      *
  89:      * @param i the index
  90:      * @param newValue the new value
  91:      */
  92:     public final void set(int i, E newValue) {
  93:         unsafe.putObjectVolatile(array, rawIndex(i), newValue);
  94:     }
  95: 
  96:     /**
  97:      * Eventually sets the element at position <tt>i</tt> to the given value.
  98:      *
  99:      * @param i the index
 100:      * @param newValue the new value
 101:      * @since 1.6
 102:      */
 103:     public final void lazySet(int i, E newValue) {
 104:         unsafe.putOrderedObject(array, rawIndex(i), newValue);
 105:     }
 106: 
 107: 
 108:     /**
 109:      * Atomically sets the element at position <tt>i</tt> to the given
 110:      * value and returns the old value.
 111:      *
 112:      * @param i the index
 113:      * @param newValue the new value
 114:      * @return the previous value
 115:      */
 116:     public final E getAndSet(int i, E newValue) {
 117:         while (true) {
 118:             E current = get(i);
 119:             if (compareAndSet(i, current, newValue))
 120:                 return current;
 121:         }
 122:     }
 123: 
 124:     /**
 125:      * Atomically sets the element at position <tt>i</tt> to the given
 126:      * updated value if the current value <tt>==</tt> the expected value.
 127:      * @param i the index
 128:      * @param expect the expected value
 129:      * @param update the new value
 130:      * @return true if successful. False return indicates that
 131:      * the actual value was not equal to the expected value.
 132:      */
 133:     public final boolean compareAndSet(int i, E expect, E update) {
 134:         return unsafe.compareAndSwapObject(array, rawIndex(i),
 135:                                          expect, update);
 136:     }
 137: 
 138:     /**
 139:      * Atomically sets the element at position <tt>i</tt> to the given
 140:      * updated value if the current value <tt>==</tt> the expected value.
 141:      * May fail spuriously and does not provide ordering guarantees,
 142:      * so is only rarely an appropriate alternative to <tt>compareAndSet</tt>.
 143:      *
 144:      * @param i the index
 145:      * @param expect the expected value
 146:      * @param update the new value
 147:      * @return true if successful.
 148:      */
 149:     public final boolean weakCompareAndSet(int i, E expect, E update) {
 150:         return compareAndSet(i, expect, update);
 151:     }
 152: 
 153:     /**
 154:      * Returns the String representation of the current values of array.
 155:      * @return the String representation of the current values of array.
 156:      */
 157:     public String toString() {
 158:         if (array.length > 0) // force volatile read
 159:             get(0);
 160:         return Arrays.toString(array);
 161:     }
 162: 
 163: }