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  * Other contributors include Andrew Wright, Jeffrey Hayes,
6  * Pat Fisher, Mike Judd.
7  */
8 
9 package jsr166;
10 
11 import junit.framework.*;
12 import java.util.Arrays;
13 import java.util.concurrent.atomic.AtomicIntegerArray;
14 
15 public class AtomicIntegerArrayTest extends JSR166TestCase {
16 
17     /**
18      * constructor creates array of given size with all elements zero
19      */
testConstructor()20     public void testConstructor() {
21         AtomicIntegerArray aa = new AtomicIntegerArray(SIZE);
22         for (int i = 0; i < SIZE; i++)
23             assertEquals(0, aa.get(i));
24     }
25 
26     /**
27      * constructor with null array throws NPE
28      */
testConstructor2NPE()29     public void testConstructor2NPE() {
30         try {
31             int[] a = null;
32             AtomicIntegerArray aa = new AtomicIntegerArray(a);
33             shouldThrow();
34         } catch (NullPointerException success) {}
35     }
36 
37     /**
38      * constructor with array is of same size and has all elements
39      */
testConstructor2()40     public void testConstructor2() {
41         int[] a = { 17, 3, -42, 99, -7 };
42         AtomicIntegerArray aa = new AtomicIntegerArray(a);
43         assertEquals(a.length, aa.length());
44         for (int i = 0; i < a.length; i++)
45             assertEquals(a[i], aa.get(i));
46     }
47 
48     /**
49      * get and set for out of bound indices throw IndexOutOfBoundsException
50      */
testIndexing()51     public void testIndexing() {
52         AtomicIntegerArray aa = new AtomicIntegerArray(SIZE);
53         for (int index : new int[] { -1, SIZE }) {
54             try {
55                 aa.get(index);
56                 shouldThrow();
57             } catch (IndexOutOfBoundsException success) {}
58             try {
59                 aa.set(index, 1);
60                 shouldThrow();
61             } catch (IndexOutOfBoundsException success) {}
62             try {
63                 aa.lazySet(index, 1);
64                 shouldThrow();
65             } catch (IndexOutOfBoundsException success) {}
66             try {
67                 aa.compareAndSet(index, 1, 2);
68                 shouldThrow();
69             } catch (IndexOutOfBoundsException success) {}
70             try {
71                 aa.weakCompareAndSet(index, 1, 2);
72                 shouldThrow();
73             } catch (IndexOutOfBoundsException success) {}
74             try {
75                 aa.getAndAdd(index, 1);
76                 shouldThrow();
77             } catch (IndexOutOfBoundsException success) {}
78             try {
79                 aa.addAndGet(index, 1);
80                 shouldThrow();
81             } catch (IndexOutOfBoundsException success) {}
82         }
83     }
84 
85     /**
86      * get returns the last value set at index
87      */
testGetSet()88     public void testGetSet() {
89         AtomicIntegerArray aa = new AtomicIntegerArray(SIZE);
90         for (int i = 0; i < SIZE; i++) {
91             aa.set(i, 1);
92             assertEquals(1, aa.get(i));
93             aa.set(i, 2);
94             assertEquals(2, aa.get(i));
95             aa.set(i, -3);
96             assertEquals(-3, aa.get(i));
97         }
98     }
99 
100     /**
101      * get returns the last value lazySet at index by same thread
102      */
testGetLazySet()103     public void testGetLazySet() {
104         AtomicIntegerArray aa = new AtomicIntegerArray(SIZE);
105         for (int i = 0; i < SIZE; i++) {
106             aa.lazySet(i, 1);
107             assertEquals(1, aa.get(i));
108             aa.lazySet(i, 2);
109             assertEquals(2, aa.get(i));
110             aa.lazySet(i, -3);
111             assertEquals(-3, aa.get(i));
112         }
113     }
114 
115     /**
116      * compareAndSet succeeds in changing value if equal to expected else fails
117      */
testCompareAndSet()118     public void testCompareAndSet() {
119         AtomicIntegerArray aa = new AtomicIntegerArray(SIZE);
120         for (int i = 0; i < SIZE; i++) {
121             aa.set(i, 1);
122             assertTrue(aa.compareAndSet(i, 1, 2));
123             assertTrue(aa.compareAndSet(i, 2, -4));
124             assertEquals(-4, aa.get(i));
125             assertFalse(aa.compareAndSet(i, -5, 7));
126             assertEquals(-4, aa.get(i));
127             assertTrue(aa.compareAndSet(i, -4, 7));
128             assertEquals(7, aa.get(i));
129         }
130     }
131 
132     /**
133      * compareAndSet in one thread enables another waiting for value
134      * to succeed
135      */
testCompareAndSetInMultipleThreads()136     public void testCompareAndSetInMultipleThreads() throws Exception {
137         final AtomicIntegerArray a = new AtomicIntegerArray(1);
138         a.set(0, 1);
139         Thread t = new Thread(new CheckedRunnable() {
140             public void realRun() {
141                 while (!a.compareAndSet(0, 2, 3))
142                     Thread.yield();
143             }});
144 
145         t.start();
146         assertTrue(a.compareAndSet(0, 1, 2));
147         t.join(LONG_DELAY_MS);
148         assertFalse(t.isAlive());
149         assertEquals(3, a.get(0));
150     }
151 
152     /**
153      * repeated weakCompareAndSet succeeds in changing value when equal
154      * to expected
155      */
testWeakCompareAndSet()156     public void testWeakCompareAndSet() {
157         AtomicIntegerArray aa = new AtomicIntegerArray(SIZE);
158         for (int i = 0; i < SIZE; i++) {
159             aa.set(i, 1);
160             while (!aa.weakCompareAndSet(i, 1, 2));
161             while (!aa.weakCompareAndSet(i, 2, -4));
162             assertEquals(-4, aa.get(i));
163             while (!aa.weakCompareAndSet(i, -4, 7));
164             assertEquals(7, aa.get(i));
165         }
166     }
167 
168     /**
169      * getAndSet returns previous value and sets to given value at given index
170      */
testGetAndSet()171     public void testGetAndSet() {
172         AtomicIntegerArray aa = new AtomicIntegerArray(SIZE);
173         for (int i = 0; i < SIZE; i++) {
174             aa.set(i, 1);
175             assertEquals(1, aa.getAndSet(i, 0));
176             assertEquals(0, aa.getAndSet(i, -10));
177             assertEquals(-10, aa.getAndSet(i, 1));
178         }
179     }
180 
181     /**
182      * getAndAdd returns previous value and adds given value
183      */
testGetAndAdd()184     public void testGetAndAdd() {
185         AtomicIntegerArray aa = new AtomicIntegerArray(SIZE);
186         for (int i = 0; i < SIZE; i++) {
187             aa.set(i, 1);
188             assertEquals(1, aa.getAndAdd(i, 2));
189             assertEquals(3, aa.get(i));
190             assertEquals(3, aa.getAndAdd(i, -4));
191             assertEquals(-1, aa.get(i));
192         }
193     }
194 
195     /**
196      * getAndDecrement returns previous value and decrements
197      */
testGetAndDecrement()198     public void testGetAndDecrement() {
199         AtomicIntegerArray aa = new AtomicIntegerArray(SIZE);
200         for (int i = 0; i < SIZE; i++) {
201             aa.set(i, 1);
202             assertEquals(1, aa.getAndDecrement(i));
203             assertEquals(0, aa.getAndDecrement(i));
204             assertEquals(-1, aa.getAndDecrement(i));
205         }
206     }
207 
208     /**
209      * getAndIncrement returns previous value and increments
210      */
testGetAndIncrement()211     public void testGetAndIncrement() {
212         AtomicIntegerArray aa = new AtomicIntegerArray(SIZE);
213         for (int i = 0; i < SIZE; i++) {
214             aa.set(i, 1);
215             assertEquals(1, aa.getAndIncrement(i));
216             assertEquals(2, aa.get(i));
217             aa.set(i, -2);
218             assertEquals(-2, aa.getAndIncrement(i));
219             assertEquals(-1, aa.getAndIncrement(i));
220             assertEquals(0, aa.getAndIncrement(i));
221             assertEquals(1, aa.get(i));
222         }
223     }
224 
225     /**
226      * addAndGet adds given value to current, and returns current value
227      */
testAddAndGet()228     public void testAddAndGet() {
229         AtomicIntegerArray aa = new AtomicIntegerArray(SIZE);
230         for (int i = 0; i < SIZE; i++) {
231             aa.set(i, 1);
232             assertEquals(3, aa.addAndGet(i, 2));
233             assertEquals(3, aa.get(i));
234             assertEquals(-1, aa.addAndGet(i, -4));
235             assertEquals(-1, aa.get(i));
236         }
237     }
238 
239     /**
240      * decrementAndGet decrements and returns current value
241      */
testDecrementAndGet()242     public void testDecrementAndGet() {
243         AtomicIntegerArray aa = new AtomicIntegerArray(SIZE);
244         for (int i = 0; i < SIZE; i++) {
245             aa.set(i, 1);
246             assertEquals(0, aa.decrementAndGet(i));
247             assertEquals(-1, aa.decrementAndGet(i));
248             assertEquals(-2, aa.decrementAndGet(i));
249             assertEquals(-2, aa.get(i));
250         }
251     }
252 
253     /**
254      * incrementAndGet increments and returns current value
255      */
testIncrementAndGet()256     public void testIncrementAndGet() {
257         AtomicIntegerArray aa = new AtomicIntegerArray(SIZE);
258         for (int i = 0; i < SIZE; i++) {
259             aa.set(i, 1);
260             assertEquals(2, aa.incrementAndGet(i));
261             assertEquals(2, aa.get(i));
262             aa.set(i, -2);
263             assertEquals(-1, aa.incrementAndGet(i));
264             assertEquals(0, aa.incrementAndGet(i));
265             assertEquals(1, aa.incrementAndGet(i));
266             assertEquals(1, aa.get(i));
267         }
268     }
269 
270     static final int COUNTDOWN = 100000;
271 
272     class Counter extends CheckedRunnable {
273         final AtomicIntegerArray aa;
274         volatile int counts;
Counter(AtomicIntegerArray a)275         Counter(AtomicIntegerArray a) { aa = a; }
realRun()276         public void realRun() {
277             for (;;) {
278                 boolean done = true;
279                 for (int i = 0; i < aa.length(); i++) {
280                     int v = aa.get(i);
281                     assertTrue(v >= 0);
282                     if (v != 0) {
283                         done = false;
284                         if (aa.compareAndSet(i, v, v-1))
285                             ++counts;
286                     }
287                 }
288                 if (done)
289                     break;
290             }
291         }
292     }
293 
294     /**
295      * Multiple threads using same array of counters successfully
296      * update a number of times equal to total count
297      */
testCountingInMultipleThreads()298     public void testCountingInMultipleThreads() throws InterruptedException {
299         final AtomicIntegerArray aa = new AtomicIntegerArray(SIZE);
300         for (int i = 0; i < SIZE; i++)
301             aa.set(i, COUNTDOWN);
302         Counter c1 = new Counter(aa);
303         Counter c2 = new Counter(aa);
304         Thread t1 = new Thread(c1);
305         Thread t2 = new Thread(c2);
306         t1.start();
307         t2.start();
308         t1.join();
309         t2.join();
310         assertEquals(c1.counts+c2.counts, SIZE * COUNTDOWN);
311     }
312 
313     /**
314      * a deserialized serialized array holds same values
315      */
testSerialization()316     public void testSerialization() throws Exception {
317         AtomicIntegerArray x = new AtomicIntegerArray(SIZE);
318         for (int i = 0; i < SIZE; i++)
319             x.set(i, -i);
320         AtomicIntegerArray y = serialClone(x);
321         assertNotSame(x, y);
322         assertEquals(x.length(), y.length());
323         for (int i = 0; i < SIZE; i++) {
324             assertEquals(x.get(i), y.get(i));
325         }
326     }
327 
328     /**
329      * toString returns current value.
330      */
testToString()331     public void testToString() {
332         int[] a = { 17, 3, -42, 99, -7 };
333         AtomicIntegerArray aa = new AtomicIntegerArray(a);
334         assertEquals(Arrays.toString(a), aa.toString());
335     }
336 
337 }
338