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: * A <tt>long</tt> array in which elements may be updated atomically.
014: * See the {@link java.util.concurrent.atomic} package specification
015: * for description of the properties of atomic variables.
016: * @since 1.5
017: * @author Doug Lea
018: */
019: public class AtomicLongArray implements java.io.Serializable {
020: private static final long serialVersionUID = -2308431214976778248L;
021:
022: // setup to use Unsafe.compareAndSwapInt for updates
023: private static final Unsafe unsafe = Unsafe.getUnsafe();
024: private static final int base = unsafe
025: .arrayBaseOffset(long[].class);
026: private static final int scale = unsafe
027: .arrayIndexScale(long[].class);
028: private final long[] 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 AtomicLongArray of given length.
038: * @param length the length of the array
039: */
040: public AtomicLongArray(int length) {
041: array = new long[length];
042: // must perform at least one volatile write to conform to JMM
043: if (length > 0)
044: unsafe.putLongVolatile(array, rawIndex(0), 0);
045: }
046:
047: /**
048: * Create a new AtomicLongArray with the same length as, and
049: * all elements copied from, the given array.
050: *
051: * @param array the array to copy elements from
052: * @throws NullPointerException if array is null
053: */
054: public AtomicLongArray(long[] array) {
055: if (array == null)
056: throw new NullPointerException();
057: int length = array.length;
058: this .array = new long[length];
059: if (length > 0) {
060: int last = length - 1;
061: for (int i = 0; i < last; ++i)
062: this .array[i] = array[i];
063: // Do the last write as volatile
064: unsafe.putLongVolatile(this .array, rawIndex(last),
065: array[last]);
066: }
067: }
068:
069: /**
070: * Returns the length of the array.
071: *
072: * @return the length of the array
073: */
074: public final int length() {
075: return array.length;
076: }
077:
078: /**
079: * Get the current value at position <tt>i</tt>.
080: *
081: * @param i the index
082: * @return the current value
083: */
084: public final long get(int i) {
085: return unsafe.getLongVolatile(array, rawIndex(i));
086: }
087:
088: /**
089: * Set the element at position <tt>i</tt> to the given value.
090: *
091: * @param i the index
092: * @param newValue the new value
093: */
094: public final void set(int i, long newValue) {
095: unsafe.putLongVolatile(array, rawIndex(i), newValue);
096: }
097:
098: /**
099: * Set the element at position <tt>i</tt> to the given value and return the
100: * old value.
101: *
102: * @param i the index
103: * @param newValue the new value
104: * @return the previous value
105: */
106: public final long getAndSet(int i, long newValue) {
107: while (true) {
108: long current = get(i);
109: if (compareAndSet(i, current, newValue))
110: return current;
111: }
112: }
113:
114: /**
115: * Atomically set the value to the given updated value
116: * if the current value <tt>==</tt> the expected value.
117: * @param i the index
118: * @param expect the expected value
119: * @param update the new value
120: * @return true if successful. False return indicates that
121: * the actual value was not equal to the expected value.
122: */
123: public final boolean compareAndSet(int i, long expect, long update) {
124: return unsafe.compareAndSwapLong(array, rawIndex(i), expect,
125: update);
126: }
127:
128: /**
129: * Atomically set the value to the given updated value
130: * if the current value <tt>==</tt> the expected value.
131: * May fail spuriously.
132: * @param i the index
133: * @param expect the expected value
134: * @param update the new value
135: * @return true if successful.
136: */
137: public final boolean weakCompareAndSet(int i, long expect,
138: long update) {
139: return compareAndSet(i, expect, update);
140: }
141:
142: /**
143: * Atomically increment by one the element at index <tt>i</tt>.
144: *
145: * @param i the index
146: * @return the previous value;
147: */
148: public final long getAndIncrement(int i) {
149: while (true) {
150: long current = get(i);
151: long next = current + 1;
152: if (compareAndSet(i, current, next))
153: return current;
154: }
155: }
156:
157: /**
158: * Atomically decrement by one the element at index <tt>i</tt>.
159: *
160: * @param i the index
161: * @return the previous value;
162: */
163: public final long getAndDecrement(int i) {
164: while (true) {
165: long current = get(i);
166: long next = current - 1;
167: if (compareAndSet(i, current, next))
168: return current;
169: }
170: }
171:
172: /**
173: * Atomically add the given value to element at index <tt>i</tt>.
174: *
175: * @param i the index
176: * @param delta the value to add
177: * @return the previous value;
178: */
179: public final long getAndAdd(int i, long delta) {
180: while (true) {
181: long current = get(i);
182: long next = current + delta;
183: if (compareAndSet(i, current, next))
184: return current;
185: }
186: }
187:
188: /**
189: * Atomically increment the element at index <tt>i</tt>.
190: *
191: * @param i the index
192: * @return the updated value;
193: */
194: public final long incrementAndGet(int i) {
195: while (true) {
196: long current = get(i);
197: long next = current + 1;
198: if (compareAndSet(i, current, next))
199: return next;
200: }
201: }
202:
203: /**
204: * Atomically decrement the element at index <tt>i</tt>.
205: *
206: * @param i the index
207: * @return the updated value;
208: */
209: public final long decrementAndGet(int i) {
210: while (true) {
211: long current = get(i);
212: long next = current - 1;
213: if (compareAndSet(i, current, next))
214: return next;
215: }
216: }
217:
218: /**
219: * Atomically add the given value to element at index <tt>i</tt>.
220: *
221: * @param i the index
222: * @param delta the value to add
223: * @return the updated value;
224: */
225: public long addAndGet(int i, long delta) {
226: while (true) {
227: long current = get(i);
228: long next = current + delta;
229: if (compareAndSet(i, current, next))
230: return next;
231: }
232: }
233:
234: /**
235: * Returns the String representation of the current values of array.
236: * @return the String representation of the current values of array.
237: */
238: public String toString() {
239: if (array.length > 0) // force volatile read
240: get(0);
241: return Arrays.toString(array);
242: }
243:
244: }
|