1. /*
  2. * @(#)AtomicLongArray.java 1.6 04/01/24
  3. *
  4. * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
  5. * SUN PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
  6. */
  7. package java.util.concurrent.atomic;
  8. import sun.misc.Unsafe;
  9. import java.util.*;
  10. /**
  11. * A <tt>long</tt> array in which elements may be updated atomically.
  12. * See the {@link java.util.concurrent.atomic} package specification
  13. * for description of the properties of atomic variables.
  14. * @since 1.5
  15. * @author Doug Lea
  16. */
  17. public class AtomicLongArray implements java.io.Serializable {
  18. private static final long serialVersionUID = -2308431214976778248L;
  19. // setup to use Unsafe.compareAndSwapInt for updates
  20. private static final Unsafe unsafe = Unsafe.getUnsafe();
  21. private static final int base = unsafe.arrayBaseOffset(long[].class);
  22. private static final int scale = unsafe.arrayIndexScale(long[].class);
  23. private final long[] array;
  24. private long rawIndex(int i) {
  25. if (i < 0 || i >= array.length)
  26. throw new IndexOutOfBoundsException("index " + i);
  27. return base + i * scale;
  28. }
  29. /**
  30. * Create a new AtomicLongArray of given length.
  31. * @param length the length of the array
  32. */
  33. public AtomicLongArray(int length) {
  34. array = new long[length];
  35. // must perform at least one volatile write to conform to JMM
  36. if (length > 0)
  37. unsafe.putLongVolatile(array, rawIndex(0), 0);
  38. }
  39. /**
  40. * Create a new AtomicLongArray with the same length as, and
  41. * all elements copied from, the given array.
  42. *
  43. * @param array the array to copy elements from
  44. * @throws NullPointerException if array is null
  45. */
  46. public AtomicLongArray(long[] array) {
  47. if (array == null)
  48. throw new NullPointerException();
  49. int length = array.length;
  50. this.array = new long[length];
  51. if (length > 0) {
  52. int last = length-1;
  53. for (int i = 0; i < last; ++i)
  54. this.array[i] = array[i];
  55. // Do the last write as volatile
  56. unsafe.putLongVolatile(this.array, rawIndex(last), array[last]);
  57. }
  58. }
  59. /**
  60. * Returns the length of the array.
  61. *
  62. * @return the length of the array
  63. */
  64. public final int length() {
  65. return array.length;
  66. }
  67. /**
  68. * Get the current value at position <tt>i</tt>.
  69. *
  70. * @param i the index
  71. * @return the current value
  72. */
  73. public final long get(int i) {
  74. return unsafe.getLongVolatile(array, rawIndex(i));
  75. }
  76. /**
  77. * Set the element at position <tt>i</tt> to the given value.
  78. *
  79. * @param i the index
  80. * @param newValue the new value
  81. */
  82. public final void set(int i, long newValue) {
  83. unsafe.putLongVolatile(array, rawIndex(i), newValue);
  84. }
  85. /**
  86. * Set the element at position <tt>i</tt> to the given value and return the
  87. * old value.
  88. *
  89. * @param i the index
  90. * @param newValue the new value
  91. * @return the previous value
  92. */
  93. public final long getAndSet(int i, long newValue) {
  94. while (true) {
  95. long current = get(i);
  96. if (compareAndSet(i, current, newValue))
  97. return current;
  98. }
  99. }
  100. /**
  101. * Atomically set the value to the given updated value
  102. * if the current value <tt>==</tt> the expected value.
  103. * @param i the index
  104. * @param expect the expected value
  105. * @param update the new value
  106. * @return true if successful. False return indicates that
  107. * the actual value was not equal to the expected value.
  108. */
  109. public final boolean compareAndSet(int i, long expect, long update) {
  110. return unsafe.compareAndSwapLong(array, rawIndex(i),
  111. expect, update);
  112. }
  113. /**
  114. * Atomically set the value to the given updated value
  115. * if the current value <tt>==</tt> the expected value.
  116. * May fail spuriously.
  117. * @param i the index
  118. * @param expect the expected value
  119. * @param update the new value
  120. * @return true if successful.
  121. */
  122. public final boolean weakCompareAndSet(int i, long expect, long update) {
  123. return compareAndSet(i, expect, update);
  124. }
  125. /**
  126. * Atomically increment by one the element at index <tt>i</tt>.
  127. *
  128. * @param i the index
  129. * @return the previous value;
  130. */
  131. public final long getAndIncrement(int i) {
  132. while (true) {
  133. long current = get(i);
  134. long next = current + 1;
  135. if (compareAndSet(i, current, next))
  136. return current;
  137. }
  138. }
  139. /**
  140. * Atomically decrement by one the element at index <tt>i</tt>.
  141. *
  142. * @param i the index
  143. * @return the previous value;
  144. */
  145. public final long getAndDecrement(int i) {
  146. while (true) {
  147. long current = get(i);
  148. long next = current - 1;
  149. if (compareAndSet(i, current, next))
  150. return current;
  151. }
  152. }
  153. /**
  154. * Atomically add the given value to element at index <tt>i</tt>.
  155. *
  156. * @param i the index
  157. * @param delta the value to add
  158. * @return the previous value;
  159. */
  160. public final long getAndAdd(int i, long delta) {
  161. while (true) {
  162. long current = get(i);
  163. long next = current + delta;
  164. if (compareAndSet(i, current, next))
  165. return current;
  166. }
  167. }
  168. /**
  169. * Atomically increment the element at index <tt>i</tt>.
  170. *
  171. * @param i the index
  172. * @return the updated value;
  173. */
  174. public final long incrementAndGet(int i) {
  175. while (true) {
  176. long current = get(i);
  177. long next = current + 1;
  178. if (compareAndSet(i, current, next))
  179. return next;
  180. }
  181. }
  182. /**
  183. * Atomically decrement the element at index <tt>i</tt>.
  184. *
  185. * @param i the index
  186. * @return the updated value;
  187. */
  188. public final long decrementAndGet(int i) {
  189. while (true) {
  190. long current = get(i);
  191. long next = current - 1;
  192. if (compareAndSet(i, current, next))
  193. return next;
  194. }
  195. }
  196. /**
  197. * Atomically add the given value to element at index <tt>i</tt>.
  198. *
  199. * @param i the index
  200. * @param delta the value to add
  201. * @return the updated value;
  202. */
  203. public long addAndGet(int i, long delta) {
  204. while (true) {
  205. long current = get(i);
  206. long next = current + delta;
  207. if (compareAndSet(i, current, next))
  208. return next;
  209. }
  210. }
  211. /**
  212. * Returns the String representation of the current values of array.
  213. * @return the String representation of the current values of array.
  214. */
  215. public String toString() {
  216. if (array.length > 0) // force volatile read
  217. get(0);
  218. return Arrays.toString(array);
  219. }
  220. }