Print this page


Split Close
Expand all
Collapse all
          --- old/src/share/classes/java/util/concurrent/atomic/AtomicReferenceArray.java
          +++ new/src/share/classes/java/util/concurrent/atomic/AtomicReferenceArray.java
↓ open down ↓ 43 lines elided ↑ open up ↑
  44   44   * variables.
  45   45   * @since 1.5
  46   46   * @author Doug Lea
  47   47   * @param <E> The base class of elements held in this array
  48   48   */
  49   49  public class AtomicReferenceArray<E> implements java.io.Serializable {
  50   50      private static final long serialVersionUID = -6209656149925076980L;
  51   51  
  52   52      private static final Unsafe unsafe = Unsafe.getUnsafe();
  53   53      private static final int base = unsafe.arrayBaseOffset(Object[].class);
  54      -    private static final int scale = unsafe.arrayIndexScale(Object[].class);
       54 +    private static final int shift;
  55   55      private final Object[] array;
  56   56  
  57      -    private long rawIndex(int i) {
       57 +    static {
       58 +        int scale = unsafe.arrayIndexScale(Object[].class);
       59 +        if ((scale & (scale - 1)) != 0)
       60 +            throw new Error("data type scale not a power of two");
       61 +        shift = 31 - Integer.numberOfLeadingZeros(scale);
       62 +    }
       63 +
       64 +    private long checkedByteOffset(int i) {
  58   65          if (i < 0 || i >= array.length)
  59   66              throw new IndexOutOfBoundsException("index " + i);
  60      -        return base + (long) i * scale;
       67 +
       68 +        return byteOffset(i);
  61   69      }
  62   70  
       71 +    private static long byteOffset(int i) {
       72 +        return ((long) i << shift) + base;
       73 +    }
       74 +
  63   75      /**
  64      -     * Creates a new AtomicReferenceArray of given length.
       76 +     * Creates a new AtomicReferenceArray of the given length, with all
       77 +     * elements initially zero.
       78 +     *
  65   79       * @param length the length of the array
  66   80       */
  67   81      public AtomicReferenceArray(int length) {
  68   82          array = new Object[length];
  69      -        // must perform at least one volatile write to conform to JMM
  70      -        if (length > 0)
  71      -            unsafe.putObjectVolatile(array, rawIndex(0), null);
  72   83      }
  73   84  
  74   85      /**
  75   86       * Creates a new AtomicReferenceArray with the same length as, and
  76   87       * all elements copied from, the given array.
  77   88       *
  78   89       * @param array the array to copy elements from
  79   90       * @throws NullPointerException if array is null
  80   91       */
  81   92      public AtomicReferenceArray(E[] array) {
  82      -        if (array == null)
  83      -            throw new NullPointerException();
  84      -        int length = array.length;
  85      -        this.array = new Object[length];
  86      -        if (length > 0) {
  87      -            int last = length-1;
  88      -            for (int i = 0; i < last; ++i)
  89      -                this.array[i] = array[i];
  90      -            // Do the last write as volatile
  91      -            E e = array[last];
  92      -            unsafe.putObjectVolatile(this.array, rawIndex(last), e);
  93      -        }
       93 +        // Visibility guaranteed by final field guarantees
       94 +        this.array = array.clone();
  94   95      }
  95   96  
  96   97      /**
  97   98       * Returns the length of the array.
  98   99       *
  99  100       * @return the length of the array
 100  101       */
 101  102      public final int length() {
 102  103          return array.length;
 103  104      }
 104  105  
 105  106      /**
 106  107       * Gets the current value at position {@code i}.
 107  108       *
 108  109       * @param i the index
 109  110       * @return the current value
 110  111       */
 111  112      public final E get(int i) {
 112      -        return (E) unsafe.getObjectVolatile(array, rawIndex(i));
      113 +        return getRaw(checkedByteOffset(i));
 113  114      }
 114  115  
      116 +    private E getRaw(long offset) {
      117 +        return (E) unsafe.getObjectVolatile(array, offset);
      118 +    }
      119 +
 115  120      /**
 116  121       * Sets the element at position {@code i} to the given value.
 117  122       *
 118  123       * @param i the index
 119  124       * @param newValue the new value
 120  125       */
 121  126      public final void set(int i, E newValue) {
 122      -        unsafe.putObjectVolatile(array, rawIndex(i), newValue);
      127 +        unsafe.putObjectVolatile(array, checkedByteOffset(i), newValue);
 123  128      }
 124  129  
 125  130      /**
 126  131       * Eventually sets the element at position {@code i} to the given value.
 127  132       *
 128  133       * @param i the index
 129  134       * @param newValue the new value
 130  135       * @since 1.6
 131  136       */
 132  137      public final void lazySet(int i, E newValue) {
 133      -        unsafe.putOrderedObject(array, rawIndex(i), newValue);
      138 +        unsafe.putOrderedObject(array, checkedByteOffset(i), newValue);
 134  139      }
 135  140  
 136  141  
 137  142      /**
 138  143       * Atomically sets the element at position {@code i} to the given
 139  144       * value and returns the old value.
 140  145       *
 141  146       * @param i the index
 142  147       * @param newValue the new value
 143  148       * @return the previous value
 144  149       */
 145  150      public final E getAndSet(int i, E newValue) {
      151 +        long offset = checkedByteOffset(i);
 146  152          while (true) {
 147      -            E current = get(i);
 148      -            if (compareAndSet(i, current, newValue))
      153 +            E current = (E) getRaw(offset);
      154 +            if (compareAndSetRaw(offset, current, newValue))
 149  155                  return current;
 150  156          }
 151  157      }
 152  158  
 153  159      /**
 154  160       * Atomically sets the element at position {@code i} to the given
 155  161       * updated value if the current value {@code ==} the expected value.
      162 +     *
 156  163       * @param i the index
 157  164       * @param expect the expected value
 158  165       * @param update the new value
 159  166       * @return true if successful. False return indicates that
 160  167       * the actual value was not equal to the expected value.
 161  168       */
 162  169      public final boolean compareAndSet(int i, E expect, E update) {
 163      -        return unsafe.compareAndSwapObject(array, rawIndex(i),
 164      -                                         expect, update);
      170 +        return compareAndSetRaw(checkedByteOffset(i), expect, update);
 165  171      }
 166  172  
      173 +    private boolean compareAndSetRaw(long offset, E expect, E update) {
      174 +        return unsafe.compareAndSwapObject(array, offset, expect, update);
      175 +    }
      176 +
 167  177      /**
 168  178       * Atomically sets the element at position {@code i} to the given
 169  179       * updated value if the current value {@code ==} the expected value.
 170  180       *
 171  181       * <p>May <a href="package-summary.html#Spurious">fail spuriously</a>
 172  182       * and does not provide ordering guarantees, so is only rarely an
 173  183       * appropriate alternative to {@code compareAndSet}.
 174  184       *
 175  185       * @param i the index
 176  186       * @param expect the expected value
 177  187       * @param update the new value
 178  188       * @return true if successful.
 179  189       */
 180  190      public final boolean weakCompareAndSet(int i, E expect, E update) {
 181  191          return compareAndSet(i, expect, update);
 182  192      }
 183  193  
 184  194      /**
 185  195       * Returns the String representation of the current values of array.
 186      -     * @return the String representation of the current values of array.
      196 +     * @return the String representation of the current values of array
 187  197       */
 188  198      public String toString() {
 189      -        if (array.length > 0) // force volatile read
 190      -            get(0);
 191      -        return Arrays.toString(array);
      199 +           int iMax = array.length - 1;
      200 +        if (iMax == -1)
      201 +            return "[]";
      202 +
      203 +        StringBuilder b = new StringBuilder();
      204 +        b.append('[');
      205 +        for (int i = 0; ; i++) {
      206 +            b.append(getRaw(byteOffset(i)));
      207 +            if (i == iMax)
      208 +                return b.append(']').toString();
      209 +            b.append(',').append(' ');
      210 +        }
 192  211      }
 193  212  
 194  213  }
    
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX