Print this page


Split Close
Expand all
Collapse all
          --- old/src/share/classes/java/util/concurrent/atomic/AtomicIntegerArray.java
          +++ new/src/share/classes/java/util/concurrent/atomic/AtomicIntegerArray.java
↓ open down ↓ 40 lines elided ↑ open up ↑
  41   41   * An {@code int} array in which elements may be updated atomically.
  42   42   * See the {@link java.util.concurrent.atomic} package
  43   43   * specification for description of the properties of atomic
  44   44   * variables.
  45   45   * @since 1.5
  46   46   * @author Doug Lea
  47   47   */
  48   48  public class AtomicIntegerArray implements java.io.Serializable {
  49   49      private static final long serialVersionUID = 2862133569453604235L;
  50   50  
  51      -   // setup to use Unsafe.compareAndSwapInt for updates
  52   51      private static final Unsafe unsafe = Unsafe.getUnsafe();
  53   52      private static final int base = unsafe.arrayBaseOffset(int[].class);
  54      -    private static final int scale = unsafe.arrayIndexScale(int[].class);
       53 +    private static final int shift;
  55   54      private final int[] array;
  56   55  
  57      -    private long rawIndex(int i) {
       56 +    static {
       57 +        int scale = unsafe.arrayIndexScale(int[].class);
       58 +        if ((scale & (scale - 1)) != 0)
       59 +            throw new Error("data type scale not a power of two");
       60 +        shift = 31 - Integer.numberOfLeadingZeros(scale);
       61 +    }
       62 +
       63 +    private long checkedByteOffset(int i) {
  58   64          if (i < 0 || i >= array.length)
  59   65              throw new IndexOutOfBoundsException("index " + i);
  60      -        return base + (long) i * scale;
       66 +
       67 +        return byteOffset(i);
  61   68      }
  62   69  
       70 +    private static long byteOffset(int i) {
       71 +        return ((long) i << shift) + base;
       72 +    }
       73 +
  63   74      /**
  64      -     * Creates a new AtomicIntegerArray of given length.
       75 +     * Creates a new AtomicIntegerArray of the given length, with all
       76 +     * elements initially zero.
  65   77       *
  66   78       * @param length the length of the array
  67   79       */
  68   80      public AtomicIntegerArray(int length) {
  69   81          array = new int[length];
  70      -        // must perform at least one volatile write to conform to JMM
  71      -        if (length > 0)
  72      -            unsafe.putIntVolatile(array, rawIndex(0), 0);
  73   82      }
  74   83  
  75   84      /**
  76   85       * Creates a new AtomicIntegerArray with the same length as, and
  77   86       * all elements copied from, the given array.
  78   87       *
  79   88       * @param array the array to copy elements from
  80   89       * @throws NullPointerException if array is null
  81   90       */
  82   91      public AtomicIntegerArray(int[] array) {
  83      -        if (array == null)
  84      -            throw new NullPointerException();
  85      -        int length = array.length;
  86      -        this.array = new int[length];
  87      -        if (length > 0) {
  88      -            int last = length-1;
  89      -            for (int i = 0; i < last; ++i)
  90      -                this.array[i] = array[i];
  91      -            // Do the last write as volatile
  92      -            unsafe.putIntVolatile(this.array, rawIndex(last), array[last]);
  93      -        }
       92 +        // Visibility guaranteed by final field guarantees
       93 +        this.array = array.clone();
  94   94      }
  95   95  
  96   96      /**
  97   97       * Returns the length of the array.
  98   98       *
  99   99       * @return the length of the array
 100  100       */
 101  101      public final int length() {
 102  102          return array.length;
 103  103      }
 104  104  
 105  105      /**
 106  106       * Gets the current value at position {@code i}.
 107  107       *
 108  108       * @param i the index
 109  109       * @return the current value
 110  110       */
 111  111      public final int get(int i) {
 112      -        return unsafe.getIntVolatile(array, rawIndex(i));
      112 +        return getRaw(checkedByteOffset(i));
 113  113      }
 114  114  
      115 +    private int getRaw(long offset) {
      116 +        return unsafe.getIntVolatile(array, offset);
      117 +    }
      118 +
 115  119      /**
 116  120       * Sets the element at position {@code i} to the given value.
 117  121       *
 118  122       * @param i the index
 119  123       * @param newValue the new value
 120  124       */
 121  125      public final void set(int i, int newValue) {
 122      -        unsafe.putIntVolatile(array, rawIndex(i), newValue);
      126 +        unsafe.putIntVolatile(array, checkedByteOffset(i), newValue);
 123  127      }
 124  128  
 125  129      /**
 126  130       * Eventually sets the element at position {@code i} to the given value.
 127  131       *
 128  132       * @param i the index
 129  133       * @param newValue the new value
 130  134       * @since 1.6
 131  135       */
 132  136      public final void lazySet(int i, int newValue) {
 133      -        unsafe.putOrderedInt(array, rawIndex(i), newValue);
      137 +        unsafe.putOrderedInt(array, checkedByteOffset(i), newValue);
 134  138      }
 135  139  
 136  140      /**
 137  141       * Atomically sets the element at position {@code i} to the given
 138  142       * value and returns the old value.
 139  143       *
 140  144       * @param i the index
 141  145       * @param newValue the new value
 142  146       * @return the previous value
 143  147       */
 144  148      public final int getAndSet(int i, int newValue) {
      149 +        long offset = checkedByteOffset(i);
 145  150          while (true) {
 146      -            int current = get(i);
 147      -            if (compareAndSet(i, current, newValue))
      151 +            int current = getRaw(offset);
      152 +            if (compareAndSetRaw(offset, current, newValue))
 148  153                  return current;
 149  154          }
 150  155      }
 151  156  
 152  157      /**
 153  158       * Atomically sets the element at position {@code i} to the given
 154  159       * updated value if the current value {@code ==} the expected value.
 155  160       *
 156  161       * @param i the index
 157  162       * @param expect the expected value
 158  163       * @param update the new value
 159  164       * @return true if successful. False return indicates that
 160  165       * the actual value was not equal to the expected value.
 161  166       */
 162  167      public final boolean compareAndSet(int i, int expect, int update) {
 163      -        return unsafe.compareAndSwapInt(array, rawIndex(i),
 164      -                                        expect, update);
      168 +        return compareAndSetRaw(checkedByteOffset(i), expect, update);
 165  169      }
 166  170  
      171 +    private boolean compareAndSetRaw(long offset, int expect, int update) {
      172 +        return unsafe.compareAndSwapInt(array, offset, expect, update);
      173 +    }
      174 +
 167  175      /**
 168  176       * Atomically sets the element at position {@code i} to the given
 169  177       * updated value if the current value {@code ==} the expected value.
 170  178       *
 171  179       * <p>May <a href="package-summary.html#Spurious">fail spuriously</a>
 172  180       * and does not provide ordering guarantees, so is only rarely an
 173  181       * appropriate alternative to {@code compareAndSet}.
 174  182       *
 175  183       * @param i the index
 176  184       * @param expect the expected value
↓ open down ↓ 4 lines elided ↑ open up ↑
 181  189          return compareAndSet(i, expect, update);
 182  190      }
 183  191  
 184  192      /**
 185  193       * Atomically increments by one the element at index {@code i}.
 186  194       *
 187  195       * @param i the index
 188  196       * @return the previous value
 189  197       */
 190  198      public final int getAndIncrement(int i) {
 191      -        while (true) {
 192      -            int current = get(i);
 193      -            int next = current + 1;
 194      -            if (compareAndSet(i, current, next))
 195      -                return current;
 196      -        }
      199 +        return getAndAdd(i, 1);
 197  200      }
 198  201  
 199  202      /**
 200  203       * Atomically decrements by one the element at index {@code i}.
 201  204       *
 202  205       * @param i the index
 203  206       * @return the previous value
 204  207       */
 205  208      public final int getAndDecrement(int i) {
 206      -        while (true) {
 207      -            int current = get(i);
 208      -            int next = current - 1;
 209      -            if (compareAndSet(i, current, next))
 210      -                return current;
 211      -        }
      209 +        return getAndAdd(i, -1);
 212  210      }
 213  211  
 214  212      /**
 215  213       * Atomically adds the given value to the element at index {@code i}.
 216  214       *
 217  215       * @param i the index
 218  216       * @param delta the value to add
 219  217       * @return the previous value
 220  218       */
 221  219      public final int getAndAdd(int i, int delta) {
      220 +        long offset = checkedByteOffset(i);
 222  221          while (true) {
 223      -            int current = get(i);
 224      -            int next = current + delta;
 225      -            if (compareAndSet(i, current, next))
      222 +            int current = getRaw(offset);
      223 +            if (compareAndSetRaw(offset, current, current + delta))
 226  224                  return current;
 227  225          }
 228  226      }
 229  227  
 230  228      /**
 231  229       * Atomically increments by one the element at index {@code i}.
 232  230       *
 233  231       * @param i the index
 234  232       * @return the updated value
 235  233       */
 236  234      public final int incrementAndGet(int i) {
 237      -        while (true) {
 238      -            int current = get(i);
 239      -            int next = current + 1;
 240      -            if (compareAndSet(i, current, next))
 241      -                return next;
 242      -        }
      235 +        return addAndGet(i, 1);
 243  236      }
 244  237  
 245  238      /**
 246  239       * Atomically decrements by one the element at index {@code i}.
 247  240       *
 248  241       * @param i the index
 249  242       * @return the updated value
 250  243       */
 251  244      public final int decrementAndGet(int i) {
 252      -        while (true) {
 253      -            int current = get(i);
 254      -            int next = current - 1;
 255      -            if (compareAndSet(i, current, next))
 256      -                return next;
 257      -        }
      245 +        return addAndGet(i, -1);
 258  246      }
 259  247  
 260  248      /**
 261  249       * Atomically adds the given value to the element at index {@code i}.
 262  250       *
 263  251       * @param i the index
 264  252       * @param delta the value to add
 265  253       * @return the updated value
 266  254       */
 267  255      public final int addAndGet(int i, int delta) {
      256 +        long offset = checkedByteOffset(i);
 268  257          while (true) {
 269      -            int current = get(i);
      258 +            int current = getRaw(offset);
 270  259              int next = current + delta;
 271      -            if (compareAndSet(i, current, next))
      260 +            if (compareAndSetRaw(offset, current, next))
 272  261                  return next;
 273  262          }
 274  263      }
 275  264  
 276  265      /**
 277  266       * Returns the String representation of the current values of array.
 278      -     * @return the String representation of the current values of array.
      267 +     * @return the String representation of the current values of array
 279  268       */
 280  269      public String toString() {
 281      -        if (array.length > 0) // force volatile read
 282      -            get(0);
 283      -        return Arrays.toString(array);
      270 +        int iMax = array.length - 1;
      271 +        if (iMax == -1)
      272 +            return "[]";
      273 +
      274 +        StringBuilder b = new StringBuilder();
      275 +        b.append('[');
      276 +        for (int i = 0; ; i++) {
      277 +            b.append(getRaw(byteOffset(i)));
      278 +            if (i == iMax)
      279 +                return b.append(']').toString();
      280 +            b.append(',').append(' ');
      281 +        }
 284  282      }
 285  283  
 286  284  }
    
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX