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 <tt>int</tt> array in which elements may be updated atomically.
014: * 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: */
020: public class AtomicIntegerArray implements java.io.Serializable {
021: private static final long serialVersionUID = 2862133569453604235L;
022:
023: // setup to use Unsafe.compareAndSwapInt for updates
024: private static final Unsafe unsafe = Unsafe.getUnsafe();
025: private static final int base = unsafe.arrayBaseOffset(int[].class);
026: private static final int scale = unsafe
027: .arrayIndexScale(int[].class);
028: private final int[] array;
029:
030: private long rawIndex(int i) {
031: if (i < 0 || i >= array.length)
032: throw new IndexOutOfBoundsException("index " + i);
033: return base + i * scale;
034: }
035:
036: /**
037: * Create a new AtomicIntegerArray of given length.
038: *
039: * @param length the length of the array
040: */
041: public AtomicIntegerArray(int length) {
042: array = new int[length];
043: // must perform at least one volatile write to conform to JMM
044: if (length > 0)
045: unsafe.putIntVolatile(array, rawIndex(0), 0);
046: }
047:
048: /**
049: * Create a new AtomicIntegerArray 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 AtomicIntegerArray(int[] array) {
056: if (array == null)
057: throw new NullPointerException();
058: int length = array.length;
059: this .array = new int[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: unsafe.putIntVolatile(this .array, rawIndex(last),
066: array[last]);
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 int get(int i) {
086: return unsafe.getIntVolatile(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, int newValue) {
096: unsafe.putIntVolatile(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 int getAndSet(int i, int newValue) {
108: while (true) {
109: int 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: *
119: * @param i the index
120: * @param expect the expected value
121: * @param update the new value
122: * @return true if successful. False return indicates that
123: * the actual value was not equal to the expected value.
124: */
125: public final boolean compareAndSet(int i, int expect, int update) {
126: return unsafe.compareAndSwapInt(array, rawIndex(i), expect,
127: update);
128: }
129:
130: /**
131: * Atomically set the value to the given updated value
132: * if the current value <tt>==</tt> the expected value.
133: * May fail spuriously.
134: *
135: * @param i the index
136: * @param expect the expected value
137: * @param update the new value
138: * @return true if successful.
139: */
140: public final boolean weakCompareAndSet(int i, int expect, int update) {
141: return compareAndSet(i, expect, update);
142: }
143:
144: /**
145: * Atomically increment by one the element at index <tt>i</tt>.
146: *
147: * @param i the index
148: * @return the previous value;
149: */
150: public final int getAndIncrement(int i) {
151: while (true) {
152: int current = get(i);
153: int next = current + 1;
154: if (compareAndSet(i, current, next))
155: return current;
156: }
157: }
158:
159: /**
160: * Atomically decrement by one the element at index <tt>i</tt>.
161: *
162: * @param i the index
163: * @return the previous value;
164: */
165: public final int getAndDecrement(int i) {
166: while (true) {
167: int current = get(i);
168: int next = current - 1;
169: if (compareAndSet(i, current, next))
170: return current;
171: }
172: }
173:
174: /**
175: * Atomically add the given value to element at index <tt>i</tt>.
176: *
177: * @param i the index
178: * @param delta the value to add
179: * @return the previous value;
180: */
181: public final int getAndAdd(int i, int delta) {
182: while (true) {
183: int current = get(i);
184: int next = current + delta;
185: if (compareAndSet(i, current, next))
186: return current;
187: }
188: }
189:
190: /**
191: * Atomically increment by one the element at index <tt>i</tt>.
192: *
193: * @param i the index
194: * @return the updated value;
195: */
196: public final int incrementAndGet(int i) {
197: while (true) {
198: int current = get(i);
199: int next = current + 1;
200: if (compareAndSet(i, current, next))
201: return next;
202: }
203: }
204:
205: /**
206: * Atomically decrement by one the element at index <tt>i</tt>.
207: *
208: * @param i the index
209: * @return the updated value;
210: */
211: public final int decrementAndGet(int i) {
212: while (true) {
213: int current = get(i);
214: int next = current - 1;
215: if (compareAndSet(i, current, next))
216: return next;
217: }
218: }
219:
220: /**
221: * Atomically add the given value to element at index <tt>i</tt>.
222: *
223: * @param i the index
224: * @param delta the value to add
225: * @return the updated value;
226: */
227: public final int addAndGet(int i, int delta) {
228: while (true) {
229: int current = get(i);
230: int next = current + delta;
231: if (compareAndSet(i, current, next))
232: return next;
233: }
234: }
235:
236: /**
237: * Returns the String representation of the current values of array.
238: * @return the String representation of the current values of array.
239: */
240: public String toString() {
241: if (array.length > 0) // force volatile read
242: get(0);
243: return Arrays.toString(array);
244: }
245:
246: }
|