ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/jsr166/jsr166/src/jdk7/java/util/concurrent/atomic/AtomicReferenceArray.java
Revision: 1.4
Committed: Mon Mar 4 16:09:25 2013 UTC (11 years, 3 months ago) by jsr166
Branch: MAIN
CVS Tags: HEAD
Changes since 1.3: +3 -3 lines
Log Message:
improve javadoc anchored text

File Contents

# Content
1 /*
2 * Written by Doug Lea with assistance from members of JCP JSR-166
3 * Expert Group and released to the public domain, as explained at
4 * http://creativecommons.org/publicdomain/zero/1.0/
5 */
6
7 package java.util.concurrent.atomic;
8
9 import java.util.Arrays;
10 import java.lang.reflect.Array;
11 import sun.misc.Unsafe;
12
13 /**
14 * An array of object references in which elements may be updated
15 * atomically. See the {@link java.util.concurrent.atomic} package
16 * specification for description of the properties of atomic
17 * variables.
18 * @since 1.5
19 * @author Doug Lea
20 * @param <E> The base class of elements held in this array
21 */
22 public class AtomicReferenceArray<E> implements java.io.Serializable {
23 private static final long serialVersionUID = -6209656149925076980L;
24
25 private static final Unsafe unsafe;
26 private static final int base;
27 private static final int shift;
28 private static final long arrayFieldOffset;
29 private final Object[] array; // must have exact type Object[]
30
31 static {
32 try {
33 unsafe = Unsafe.getUnsafe();
34 arrayFieldOffset = unsafe.objectFieldOffset
35 (AtomicReferenceArray.class.getDeclaredField("array"));
36 base = unsafe.arrayBaseOffset(Object[].class);
37 int scale = unsafe.arrayIndexScale(Object[].class);
38 if ((scale & (scale - 1)) != 0)
39 throw new Error("data type scale not a power of two");
40 shift = 31 - Integer.numberOfLeadingZeros(scale);
41 } catch (Exception e) {
42 throw new Error(e);
43 }
44 }
45
46 private long checkedByteOffset(int i) {
47 if (i < 0 || i >= array.length)
48 throw new IndexOutOfBoundsException("index " + i);
49
50 return byteOffset(i);
51 }
52
53 private static long byteOffset(int i) {
54 return ((long) i << shift) + base;
55 }
56
57 /**
58 * Creates a new AtomicReferenceArray of the given length, with all
59 * elements initially null.
60 *
61 * @param length the length of the array
62 */
63 public AtomicReferenceArray(int length) {
64 array = new Object[length];
65 }
66
67 /**
68 * Creates a new AtomicReferenceArray with the same length as, and
69 * all elements copied from, the given array.
70 *
71 * @param array the array to copy elements from
72 * @throws NullPointerException if array is null
73 */
74 public AtomicReferenceArray(E[] array) {
75 // Visibility guaranteed by final field guarantees
76 this.array = Arrays.copyOf(array, array.length, Object[].class);
77 }
78
79 /**
80 * Returns the length of the array.
81 *
82 * @return the length of the array
83 */
84 public final int length() {
85 return array.length;
86 }
87
88 /**
89 * Gets the current value at position {@code i}.
90 *
91 * @param i the index
92 * @return the current value
93 */
94 public final E get(int i) {
95 return getRaw(checkedByteOffset(i));
96 }
97
98 @SuppressWarnings("unchecked")
99 private E getRaw(long offset) {
100 return (E) unsafe.getObjectVolatile(array, offset);
101 }
102
103 /**
104 * Sets the element at position {@code i} to the given value.
105 *
106 * @param i the index
107 * @param newValue the new value
108 */
109 public final void set(int i, E newValue) {
110 unsafe.putObjectVolatile(array, checkedByteOffset(i), newValue);
111 }
112
113 /**
114 * Eventually sets the element at position {@code i} to the given value.
115 *
116 * @param i the index
117 * @param newValue the new value
118 * @since 1.6
119 */
120 public final void lazySet(int i, E newValue) {
121 unsafe.putOrderedObject(array, checkedByteOffset(i), newValue);
122 }
123
124 /**
125 * Atomically sets the element at position {@code i} to the given
126 * value and returns the old value.
127 *
128 * @param i the index
129 * @param newValue the new value
130 * @return the previous value
131 */
132 public final E getAndSet(int i, E newValue) {
133 long offset = checkedByteOffset(i);
134 while (true) {
135 E current = getRaw(offset);
136 if (compareAndSetRaw(offset, current, newValue))
137 return current;
138 }
139 }
140
141 /**
142 * Atomically sets the element at position {@code i} to the given
143 * updated value if the current value {@code ==} the expected value.
144 *
145 * @param i the index
146 * @param expect the expected value
147 * @param update the new value
148 * @return true if successful. False return indicates that
149 * the actual value was not equal to the expected value.
150 */
151 public final boolean compareAndSet(int i, E expect, E update) {
152 return compareAndSetRaw(checkedByteOffset(i), expect, update);
153 }
154
155 private boolean compareAndSetRaw(long offset, E expect, E update) {
156 return unsafe.compareAndSwapObject(array, offset, expect, update);
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 * <p><a href="package-summary.html#weakCompareAndSet">May fail
164 * spuriously and does not provide ordering guarantees</a>, so is
165 * only rarely an appropriate alternative to {@code compareAndSet}.
166 *
167 * @param i the index
168 * @param expect the expected value
169 * @param update the new value
170 * @return true if successful
171 */
172 public final boolean weakCompareAndSet(int i, E expect, E update) {
173 return compareAndSet(i, expect, update);
174 }
175
176 /**
177 * Returns the String representation of the current values of array.
178 * @return the String representation of the current values of array
179 */
180 public String toString() {
181 int iMax = array.length - 1;
182 if (iMax == -1)
183 return "[]";
184
185 StringBuilder b = new StringBuilder();
186 b.append('[');
187 for (int i = 0; ; i++) {
188 b.append(getRaw(byteOffset(i)));
189 if (i == iMax)
190 return b.append(']').toString();
191 b.append(',').append(' ');
192 }
193 }
194
195 /**
196 * Reconstitutes the instance from a stream (that is, deserializes it).
197 */
198 private void readObject(java.io.ObjectInputStream s)
199 throws java.io.IOException, ClassNotFoundException,
200 java.io.InvalidObjectException {
201 // Note: This must be changed if any additional fields are defined
202 Object a = s.readFields().get("array", null);
203 if (a == null || !a.getClass().isArray())
204 throw new java.io.InvalidObjectException("Not array type");
205 if (a.getClass() != Object[].class)
206 a = Arrays.copyOf((Object[])a, Array.getLength(a), Object[].class);
207 unsafe.putObjectVolatile(this, arrayFieldOffset, a);
208 }
209
210 }