001: /*
002: * Written by Doug Lea with assistance from members of JCP JSR-166
003: * Expert Group and released to the public domain, as explained at
004: * http://creativecommons.org/licenses/publicdomain
005: */
006:
007: package java.util.concurrent.atomic;
008:
009: import sun.misc.Unsafe;
010: import java.util.*;
011:
012: /**
013: * An array of object references in which elements may be updated
014: * atomically. See the {@link java.util.concurrent.atomic} package
015: * specification for description of the properties of atomic
016: * variables.
017: * @since 1.5
018: * @author Doug Lea
019: * @param <E> The base class of elements held in this array
020: */
021: public class AtomicReferenceArray<E> implements java.io.Serializable {
022: private static final long serialVersionUID = -6209656149925076980L;
023:
024: private static final Unsafe unsafe = Unsafe.getUnsafe();
025: private static final int base = unsafe
026: .arrayBaseOffset(Object[].class);
027: private static final int scale = unsafe
028: .arrayIndexScale(Object[].class);
029: private final Object[] array;
030:
031: private long rawIndex(int i) {
032: if (i < 0 || i >= array.length)
033: throw new IndexOutOfBoundsException("index " + i);
034: return base + i * scale;
035: }
036:
037: /**
038: * Create a new AtomicReferenceArray of given length.
039: * @param length the length of the array
040: */
041: public AtomicReferenceArray(int length) {
042: array = new Object[length];
043: // must perform at least one volatile write to conform to JMM
044: if (length > 0)
045: unsafe.putObjectVolatile(array, rawIndex(0), null);
046: }
047:
048: /**
049: * Create a new AtomicReferenceArray with the same length as, and
050: * all elements copied from, the given array.
051: *
052: * @param array the array to copy elements from
053: * @throws NullPointerException if array is null
054: */
055: public AtomicReferenceArray(E[] array) {
056: if (array == null)
057: throw new NullPointerException();
058: int length = array.length;
059: this .array = new Object[length];
060: if (length > 0) {
061: int last = length - 1;
062: for (int i = 0; i < last; ++i)
063: this .array[i] = array[i];
064: // Do the last write as volatile
065: E e = array[last];
066: unsafe.putObjectVolatile(this .array, rawIndex(last), e);
067: }
068: }
069:
070: /**
071: * Returns the length of the array.
072: *
073: * @return the length of the array
074: */
075: public final int length() {
076: return array.length;
077: }
078:
079: /**
080: * Get the current value at position <tt>i</tt>.
081: *
082: * @param i the index
083: * @return the current value
084: */
085: public final E get(int i) {
086: return (E) unsafe.getObjectVolatile(array, rawIndex(i));
087: }
088:
089: /**
090: * Set the element at position <tt>i</tt> to the given value.
091: *
092: * @param i the index
093: * @param newValue the new value
094: */
095: public final void set(int i, E newValue) {
096: unsafe.putObjectVolatile(array, rawIndex(i), newValue);
097: }
098:
099: /**
100: * Set the element at position <tt>i</tt> to the given value and return the
101: * old value.
102: *
103: * @param i the index
104: * @param newValue the new value
105: * @return the previous value
106: */
107: public final E getAndSet(int i, E newValue) {
108: while (true) {
109: E current = get(i);
110: if (compareAndSet(i, current, newValue))
111: return current;
112: }
113: }
114:
115: /**
116: * Atomically set the value to the given updated value
117: * if the current value <tt>==</tt> the expected value.
118: * @param i the index
119: * @param expect the expected value
120: * @param update the new value
121: * @return true if successful. False return indicates that
122: * the actual value was not equal to the expected value.
123: */
124: public final boolean compareAndSet(int i, E expect, E update) {
125: return unsafe.compareAndSwapObject(array, rawIndex(i), expect,
126: update);
127: }
128:
129: /**
130: * Atomically set the value to the given updated value
131: * if the current value <tt>==</tt> the expected value.
132: * May fail spuriously.
133: * @param i the index
134: * @param expect the expected value
135: * @param update the new value
136: * @return true if successful.
137: */
138: public final boolean weakCompareAndSet(int i, E expect, E update) {
139: return compareAndSet(i, expect, update);
140: }
141:
142: /**
143: * Returns the String representation of the current values of array.
144: * @return the String representation of the current values of array.
145: */
146: public String toString() {
147: if (array.length > 0) // force volatile read
148: get(0);
149: return Arrays.toString(array);
150: }
151:
152: }
|