Print this page


Split Close
Expand all
Collapse all
          --- old/src/share/classes/java/util/concurrent/atomic/AtomicLongArray.java
          +++ new/src/share/classes/java/util/concurrent/atomic/AtomicLongArray.java
↓ open down ↓ 39 lines elided ↑ open up ↑
  40   40  /**
  41   41   * A {@code long} array in which elements may be updated atomically.
  42   42   * See the {@link java.util.concurrent.atomic} package specification
  43   43   * for description of the properties of atomic variables.
  44   44   * @since 1.5
  45   45   * @author Doug Lea
  46   46   */
  47   47  public class AtomicLongArray implements java.io.Serializable {
  48   48      private static final long serialVersionUID = -2308431214976778248L;
  49   49  
  50      -    // setup to use Unsafe.compareAndSwapInt for updates
  51   50      private static final Unsafe unsafe = Unsafe.getUnsafe();
  52   51      private static final int base = unsafe.arrayBaseOffset(long[].class);
  53      -    private static final int scale = unsafe.arrayIndexScale(long[].class);
       52 +    private static final int shift;
  54   53      private final long[] array;
  55   54  
  56      -    private long rawIndex(int i) {
       55 +    static {
       56 +        int scale = unsafe.arrayIndexScale(long[].class);
       57 +        if ((scale & (scale - 1)) != 0)
       58 +            throw new Error("data type scale not a power of two");
       59 +        shift = 31 - Integer.numberOfLeadingZeros(scale);
       60 +    }
       61 +
       62 +    private long checkedByteOffset(int i) {
  57   63          if (i < 0 || i >= array.length)
  58   64              throw new IndexOutOfBoundsException("index " + i);
  59      -        return base + (long) i * scale;
       65 +
       66 +        return byteOffset(i);
  60   67      }
  61   68  
       69 +    private static long byteOffset(int i) {
       70 +        return ((long) i << shift) + base;
       71 +    }
       72 +
  62   73      /**
  63      -     * Creates a new AtomicLongArray of given length.
       74 +     * Creates a new AtomicLongArray of the given length, with all
       75 +     * elements initially zero.
  64   76       *
  65   77       * @param length the length of the array
  66   78       */
  67   79      public AtomicLongArray(int length) {
  68   80          array = new long[length];
  69      -        // must perform at least one volatile write to conform to JMM
  70      -        if (length > 0)
  71      -            unsafe.putLongVolatile(array, rawIndex(0), 0);
  72   81      }
  73   82  
  74   83      /**
  75   84       * Creates a new AtomicLongArray with the same length as, and
  76   85       * all elements copied from, the given array.
  77   86       *
  78   87       * @param array the array to copy elements from
  79   88       * @throws NullPointerException if array is null
  80   89       */
  81   90      public AtomicLongArray(long[] array) {
  82      -        if (array == null)
  83      -            throw new NullPointerException();
  84      -        int length = array.length;
  85      -        this.array = new long[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      -            unsafe.putLongVolatile(this.array, rawIndex(last), array[last]);
  92      -        }
       91 +        // Visibility guaranteed by final field guarantees
       92 +        this.array = array.clone();
  93   93      }
  94   94  
  95   95      /**
  96   96       * Returns the length of the array.
  97   97       *
  98   98       * @return the length of the array
  99   99       */
 100  100      public final int length() {
 101  101          return array.length;
 102  102      }
 103  103  
 104  104      /**
 105  105       * Gets the current value at position {@code i}.
 106  106       *
 107  107       * @param i the index
 108  108       * @return the current value
 109  109       */
 110  110      public final long get(int i) {
 111      -        return unsafe.getLongVolatile(array, rawIndex(i));
      111 +        return getRaw(checkedByteOffset(i));
 112  112      }
 113  113  
      114 +    private long getRaw(long offset) {
      115 +        return unsafe.getLongVolatile(array, offset);
      116 +    }
      117 +
 114  118      /**
 115  119       * Sets the element at position {@code i} to the given value.
 116  120       *
 117  121       * @param i the index
 118  122       * @param newValue the new value
 119  123       */
 120  124      public final void set(int i, long newValue) {
 121      -        unsafe.putLongVolatile(array, rawIndex(i), newValue);
      125 +        unsafe.putLongVolatile(array, checkedByteOffset(i), newValue);
 122  126      }
 123  127  
 124  128      /**
 125  129       * Eventually sets the element at position {@code i} to the given value.
 126  130       *
 127  131       * @param i the index
 128  132       * @param newValue the new value
 129  133       * @since 1.6
 130  134       */
 131  135      public final void lazySet(int i, long newValue) {
 132      -        unsafe.putOrderedLong(array, rawIndex(i), newValue);
      136 +        unsafe.putOrderedLong(array, checkedByteOffset(i), newValue);
 133  137      }
 134  138  
 135  139  
 136  140      /**
 137  141       * Atomically sets the element at position {@code i} to the given value
 138  142       * 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 long getAndSet(int i, long newValue) {
      149 +        long offset = checkedByteOffset(i);
 145  150          while (true) {
 146      -            long current = get(i);
 147      -            if (compareAndSet(i, current, newValue))
      151 +            long current = getRaw(offset);
      152 +            if (compareAndSetRaw(offset, current, newValue))
 148  153                  return current;
 149  154          }
 150  155      }
 151  156  
 152  157      /**
 153      -     * Atomically sets the value to the given updated value
 154      -     * if the current value {@code ==} the expected value.
      158 +     * Atomically sets the element at position {@code i} to the given
      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, long expect, long update) {
 163      -        return unsafe.compareAndSwapLong(array, rawIndex(i),
 164      -                                         expect, update);
      168 +        return compareAndSetRaw(checkedByteOffset(i), expect, update);
 165  169      }
 166  170  
      171 +    private boolean compareAndSetRaw(long offset, long expect, long update) {
      172 +        return unsafe.compareAndSwapLong(array, offset, expect, update);
      173 +    }
      174 +
 167  175      /**
 168      -     * Atomically sets the value to the given updated value
 169      -     * if the current value {@code ==} the expected value.
      176 +     * Atomically sets the element at position {@code i} to the given
      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
 177  185       * @param update the new value
 178  186       * @return true if successful.
 179  187       */
↓ open down ↓ 1 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 long getAndIncrement(int i) {
 191      -        while (true) {
 192      -            long current = get(i);
 193      -            long 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 long getAndDecrement(int i) {
 206      -        while (true) {
 207      -            long current = get(i);
 208      -            long 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 long getAndAdd(int i, long delta) {
      220 +        long offset = checkedByteOffset(i);
 222  221          while (true) {
 223      -            long current = get(i);
 224      -            long next = current + delta;
 225      -            if (compareAndSet(i, current, next))
      222 +            long 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 long incrementAndGet(int i) {
 237      -        while (true) {
 238      -            long current = get(i);
 239      -            long 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 long decrementAndGet(int i) {
 252      -        while (true) {
 253      -            long current = get(i);
 254      -            long 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 long addAndGet(int i, long delta) {
      256 +        long offset = checkedByteOffset(i);
 268  257          while (true) {
 269      -            long current = get(i);
      258 +            long current = getRaw(offset);
 270  259              long 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