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