rt/emul/compact/src/main/java/java/util/concurrent/atomic/AtomicReferenceArray.java
author Jaroslav Tulach <jtulach@netbeans.org>
Thu, 03 Oct 2013 15:40:35 +0200
branchjdk7-b147
changeset 1334 588d5bf7a560
child 1338 aa70afac4eca
permissions -rw-r--r--
Set of JDK classes needed to run javac
     1 /*
     2  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
     3  *
     4  * This code is free software; you can redistribute it and/or modify it
     5  * under the terms of the GNU General Public License version 2 only, as
     6  * published by the Free Software Foundation.  Oracle designates this
     7  * particular file as subject to the "Classpath" exception as provided
     8  * by Oracle in the LICENSE file that accompanied this code.
     9  *
    10  * This code is distributed in the hope that it will be useful, but WITHOUT
    11  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
    12  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
    13  * version 2 for more details (a copy is included in the LICENSE file that
    14  * accompanied this code).
    15  *
    16  * You should have received a copy of the GNU General Public License version
    17  * 2 along with this work; if not, write to the Free Software Foundation,
    18  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
    19  *
    20  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
    21  * or visit www.oracle.com if you need additional information or have any
    22  * questions.
    23  */
    24 
    25 /*
    26  * This file is available under and governed by the GNU General Public
    27  * License version 2 only, as published by the Free Software Foundation.
    28  * However, the following notice accompanied the original version of this
    29  * file:
    30  *
    31  * Written by Doug Lea with assistance from members of JCP JSR-166
    32  * Expert Group and released to the public domain, as explained at
    33  * http://creativecommons.org/publicdomain/zero/1.0/
    34  */
    35 
    36 package java.util.concurrent.atomic;
    37 import sun.misc.Unsafe;
    38 import java.util.*;
    39 
    40 /**
    41  * An array of object references in which elements may be updated
    42  * atomically.  See the {@link java.util.concurrent.atomic} package
    43  * specification for description of the properties of atomic
    44  * variables.
    45  * @since 1.5
    46  * @author Doug Lea
    47  * @param <E> The base class of elements held in this array
    48  */
    49 public class AtomicReferenceArray<E> implements java.io.Serializable {
    50     private static final long serialVersionUID = -6209656149925076980L;
    51 
    52     private static final Unsafe unsafe = Unsafe.getUnsafe();
    53     private static final int base = unsafe.arrayBaseOffset(Object[].class);
    54     private static final int shift;
    55     private final Object[] array;
    56 
    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) {
    65         if (i < 0 || i >= array.length)
    66             throw new IndexOutOfBoundsException("index " + i);
    67 
    68         return byteOffset(i);
    69     }
    70 
    71     private static long byteOffset(int i) {
    72         return ((long) i << shift) + base;
    73     }
    74 
    75     /**
    76      * Creates a new AtomicReferenceArray of the given length, with all
    77      * elements initially null.
    78      *
    79      * @param length the length of the array
    80      */
    81     public AtomicReferenceArray(int length) {
    82         array = new Object[length];
    83     }
    84 
    85     /**
    86      * Creates a new AtomicReferenceArray with the same length as, and
    87      * all elements copied from, the given array.
    88      *
    89      * @param array the array to copy elements from
    90      * @throws NullPointerException if array is null
    91      */
    92     public AtomicReferenceArray(E[] array) {
    93         // Visibility guaranteed by final field guarantees
    94         this.array = array.clone();
    95     }
    96 
    97     /**
    98      * Returns the length of the array.
    99      *
   100      * @return the length of the array
   101      */
   102     public final int length() {
   103         return array.length;
   104     }
   105 
   106     /**
   107      * Gets the current value at position {@code i}.
   108      *
   109      * @param i the index
   110      * @return the current value
   111      */
   112     public final E get(int i) {
   113         return getRaw(checkedByteOffset(i));
   114     }
   115 
   116     private E getRaw(long offset) {
   117         return (E) unsafe.getObjectVolatile(array, offset);
   118     }
   119 
   120     /**
   121      * Sets the element at position {@code i} to the given value.
   122      *
   123      * @param i the index
   124      * @param newValue the new value
   125      */
   126     public final void set(int i, E newValue) {
   127         unsafe.putObjectVolatile(array, checkedByteOffset(i), newValue);
   128     }
   129 
   130     /**
   131      * Eventually sets the element at position {@code i} to the given value.
   132      *
   133      * @param i the index
   134      * @param newValue the new value
   135      * @since 1.6
   136      */
   137     public final void lazySet(int i, E newValue) {
   138         unsafe.putOrderedObject(array, checkedByteOffset(i), newValue);
   139     }
   140 
   141 
   142     /**
   143      * Atomically sets the element at position {@code i} to the given
   144      * value and returns the old value.
   145      *
   146      * @param i the index
   147      * @param newValue the new value
   148      * @return the previous value
   149      */
   150     public final E getAndSet(int i, E newValue) {
   151         long offset = checkedByteOffset(i);
   152         while (true) {
   153             E current = (E) getRaw(offset);
   154             if (compareAndSetRaw(offset, current, newValue))
   155                 return current;
   156         }
   157     }
   158 
   159     /**
   160      * Atomically sets the element at position {@code i} to the given
   161      * updated value if the current value {@code ==} the expected value.
   162      *
   163      * @param i the index
   164      * @param expect the expected value
   165      * @param update the new value
   166      * @return true if successful. False return indicates that
   167      * the actual value was not equal to the expected value.
   168      */
   169     public final boolean compareAndSet(int i, E expect, E update) {
   170         return compareAndSetRaw(checkedByteOffset(i), expect, update);
   171     }
   172 
   173     private boolean compareAndSetRaw(long offset, E expect, E update) {
   174         return unsafe.compareAndSwapObject(array, offset, expect, update);
   175     }
   176 
   177     /**
   178      * Atomically sets the element at position {@code i} to the given
   179      * updated value if the current value {@code ==} the expected value.
   180      *
   181      * <p>May <a href="package-summary.html#Spurious">fail spuriously</a>
   182      * and does not provide ordering guarantees, so is only rarely an
   183      * appropriate alternative to {@code compareAndSet}.
   184      *
   185      * @param i the index
   186      * @param expect the expected value
   187      * @param update the new value
   188      * @return true if successful.
   189      */
   190     public final boolean weakCompareAndSet(int i, E expect, E update) {
   191         return compareAndSet(i, expect, update);
   192     }
   193 
   194     /**
   195      * Returns the String representation of the current values of array.
   196      * @return the String representation of the current values of array
   197      */
   198     public String toString() {
   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         }
   211     }
   212 
   213 }