• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Written by Doug Lea and Martin Buchholz with assistance from
3  * members of JCP JSR-166 Expert Group and released to the public
4  * domain, as explained at
5  * http://creativecommons.org/publicdomain/zero/1.0/
6  */
7 
8 /*
9  * Source:
10  * http://gee.cs.oswego.edu/cgi-bin/viewcvs.cgi/jsr166/src/test/tck-jsr166e/AtomicDoubleArrayTest.java?revision=1.13
11  * (Modified to adapt to guava coding conventions)
12  */
13 
14 package com.google.common.util.concurrent;
15 
16 import static java.lang.Math.max;
17 import static org.junit.Assert.assertThrows;
18 
19 import com.google.common.annotations.GwtIncompatible;
20 import com.google.common.testing.NullPointerTester;
21 import java.util.Arrays;
22 
23 /** Unit test for {@link AtomicDoubleArray}. */
24 public class AtomicDoubleArrayTest extends JSR166TestCase {
25 
26   private static final double[] VALUES = {
27     Double.NEGATIVE_INFINITY,
28     -Double.MAX_VALUE,
29     (double) Long.MIN_VALUE,
30     (double) Integer.MIN_VALUE,
31     -Math.PI,
32     -1.0,
33     -Double.MIN_VALUE,
34     -0.0,
35     +0.0,
36     Double.MIN_VALUE,
37     1.0,
38     Math.PI,
39     (double) Integer.MAX_VALUE,
40     (double) Long.MAX_VALUE,
41     Double.MAX_VALUE,
42     Double.POSITIVE_INFINITY,
43     Double.NaN,
44     Float.MAX_VALUE,
45   };
46 
47   /** The notion of equality used by AtomicDoubleArray */
bitEquals(double x, double y)48   static boolean bitEquals(double x, double y) {
49     return Double.doubleToRawLongBits(x) == Double.doubleToRawLongBits(y);
50   }
51 
assertBitEquals(double x, double y)52   static void assertBitEquals(double x, double y) {
53     assertEquals(Double.doubleToRawLongBits(x), Double.doubleToRawLongBits(y));
54   }
55 
56   @GwtIncompatible // NullPointerTester
testNulls()57   public void testNulls() {
58     new NullPointerTester().testAllPublicStaticMethods(AtomicDoubleArray.class);
59     new NullPointerTester().testAllPublicConstructors(AtomicDoubleArray.class);
60     new NullPointerTester().testAllPublicInstanceMethods(new AtomicDoubleArray(1));
61   }
62 
63   /** constructor creates array of given size with all elements zero */
testConstructor()64   public void testConstructor() {
65     AtomicDoubleArray aa = new AtomicDoubleArray(SIZE);
66     for (int i = 0; i < SIZE; i++) {
67       assertBitEquals(0.0, aa.get(i));
68     }
69   }
70 
71   /** constructor with null array throws NPE */
testConstructor2NPE()72   public void testConstructor2NPE() {
73     double[] a = null;
74     assertThrows(NullPointerException.class, () -> new AtomicDoubleArray(a));
75   }
76 
77   /** constructor with array is of same size and has all elements */
testConstructor2()78   public void testConstructor2() {
79     AtomicDoubleArray aa = new AtomicDoubleArray(VALUES);
80     assertEquals(VALUES.length, aa.length());
81     for (int i = 0; i < VALUES.length; i++) {
82       assertBitEquals(VALUES[i], aa.get(i));
83     }
84   }
85 
86   /** constructor with empty array has size 0 and contains no elements */
testConstructorEmptyArray()87   public void testConstructorEmptyArray() {
88     AtomicDoubleArray aa = new AtomicDoubleArray(new double[0]);
89     assertEquals(0, aa.length());
90     assertThrows(IndexOutOfBoundsException.class, () -> aa.get(0));
91   }
92 
93   /** constructor with length zero has size 0 and contains no elements */
testConstructorZeroLength()94   public void testConstructorZeroLength() {
95     AtomicDoubleArray aa = new AtomicDoubleArray(0);
96     assertEquals(0, aa.length());
97     assertThrows(IndexOutOfBoundsException.class, () -> aa.get(0));
98   }
99 
100   /** get and set for out of bound indices throw IndexOutOfBoundsException */
testIndexing()101   public void testIndexing() {
102     AtomicDoubleArray aa = new AtomicDoubleArray(SIZE);
103     for (int index : new int[] {-1, SIZE}) {
104       assertThrows(IndexOutOfBoundsException.class, () -> aa.get(index));
105       assertThrows(IndexOutOfBoundsException.class, () -> aa.set(index, 1.0));
106       assertThrows(IndexOutOfBoundsException.class, () -> aa.lazySet(index, 1.0));
107       assertThrows(IndexOutOfBoundsException.class, () -> aa.compareAndSet(index, 1.0, 2.0));
108       assertThrows(IndexOutOfBoundsException.class, () -> aa.weakCompareAndSet(index, 1.0, 2.0));
109       assertThrows(IndexOutOfBoundsException.class, () -> aa.getAndAdd(index, 1.0));
110       assertThrows(IndexOutOfBoundsException.class, () -> aa.addAndGet(index, 1.0));
111     }
112   }
113 
114   /** get returns the last value set at index */
testGetSet()115   public void testGetSet() {
116     AtomicDoubleArray aa = new AtomicDoubleArray(VALUES.length);
117     for (int i = 0; i < VALUES.length; i++) {
118       assertBitEquals(0.0, aa.get(i));
119       aa.set(i, VALUES[i]);
120       assertBitEquals(VALUES[i], aa.get(i));
121       aa.set(i, -3.0);
122       assertBitEquals(-3.0, aa.get(i));
123     }
124   }
125 
126   /** get returns the last value lazySet at index by same thread */
testGetLazySet()127   public void testGetLazySet() {
128     AtomicDoubleArray aa = new AtomicDoubleArray(VALUES.length);
129     for (int i = 0; i < VALUES.length; i++) {
130       assertBitEquals(0.0, aa.get(i));
131       aa.lazySet(i, VALUES[i]);
132       assertBitEquals(VALUES[i], aa.get(i));
133       aa.lazySet(i, -3.0);
134       assertBitEquals(-3.0, aa.get(i));
135     }
136   }
137 
138   /** compareAndSet succeeds in changing value if equal to expected else fails */
testCompareAndSet()139   public void testCompareAndSet() {
140     AtomicDoubleArray aa = new AtomicDoubleArray(SIZE);
141     for (int i : new int[] {0, SIZE - 1}) {
142       double prev = 0.0;
143       double unused = Math.E + Math.PI;
144       for (double x : VALUES) {
145         assertBitEquals(prev, aa.get(i));
146         assertFalse(aa.compareAndSet(i, unused, x));
147         assertBitEquals(prev, aa.get(i));
148         assertTrue(aa.compareAndSet(i, prev, x));
149         assertBitEquals(x, aa.get(i));
150         prev = x;
151       }
152     }
153   }
154 
155   /** compareAndSet in one thread enables another waiting for value to succeed */
testCompareAndSetInMultipleThreads()156   public void testCompareAndSetInMultipleThreads() throws InterruptedException {
157     final AtomicDoubleArray a = new AtomicDoubleArray(1);
158     a.set(0, 1.0);
159     Thread t =
160         newStartedThread(
161             new CheckedRunnable() {
162               @Override
163               public void realRun() {
164                 while (!a.compareAndSet(0, 2.0, 3.0)) {
165                   Thread.yield();
166                 }
167               }
168             });
169 
170     assertTrue(a.compareAndSet(0, 1.0, 2.0));
171     awaitTermination(t);
172     assertBitEquals(3.0, a.get(0));
173   }
174 
175   /** repeated weakCompareAndSet succeeds in changing value when equal to expected */
testWeakCompareAndSet()176   public void testWeakCompareAndSet() {
177     AtomicDoubleArray aa = new AtomicDoubleArray(SIZE);
178     for (int i : new int[] {0, SIZE - 1}) {
179       double prev = 0.0;
180       double unused = Math.E + Math.PI;
181       for (double x : VALUES) {
182         assertBitEquals(prev, aa.get(i));
183         assertFalse(aa.weakCompareAndSet(i, unused, x));
184         assertBitEquals(prev, aa.get(i));
185         while (!aa.weakCompareAndSet(i, prev, x)) {
186           ;
187         }
188         assertBitEquals(x, aa.get(i));
189         prev = x;
190       }
191     }
192   }
193 
194   /** getAndSet returns previous value and sets to given value at given index */
testGetAndSet()195   public void testGetAndSet() {
196     AtomicDoubleArray aa = new AtomicDoubleArray(SIZE);
197     for (int i : new int[] {0, SIZE - 1}) {
198       double prev = 0.0;
199       for (double x : VALUES) {
200         assertBitEquals(prev, aa.getAndSet(i, x));
201         prev = x;
202       }
203     }
204   }
205 
206   /** getAndAdd returns previous value and adds given value */
testGetAndAdd()207   public void testGetAndAdd() {
208     AtomicDoubleArray aa = new AtomicDoubleArray(SIZE);
209     for (int i : new int[] {0, SIZE - 1}) {
210       for (double x : VALUES) {
211         for (double y : VALUES) {
212           aa.set(i, x);
213           double z = aa.getAndAdd(i, y);
214           assertBitEquals(x, z);
215           assertBitEquals(x + y, aa.get(i));
216         }
217       }
218     }
219   }
220 
221   /** addAndGet adds given value to current, and returns current value */
testAddAndGet()222   public void testAddAndGet() {
223     AtomicDoubleArray aa = new AtomicDoubleArray(SIZE);
224     for (int i : new int[] {0, SIZE - 1}) {
225       for (double x : VALUES) {
226         for (double y : VALUES) {
227           aa.set(i, x);
228           double z = aa.addAndGet(i, y);
229           assertBitEquals(x + y, z);
230           assertBitEquals(x + y, aa.get(i));
231         }
232       }
233     }
234   }
235 
236   /** getAndAccumulate with sum adds given value to current, and returns previous value */
testGetAndAccumulateWithSum()237   public void testGetAndAccumulateWithSum() {
238     AtomicDoubleArray aa = new AtomicDoubleArray(SIZE);
239     for (int i : new int[] {0, SIZE - 1}) {
240       for (double x : VALUES) {
241         for (double y : VALUES) {
242           aa.set(i, x);
243           double z = aa.getAndAccumulate(i, y, Double::sum);
244           assertBitEquals(x, z);
245           assertBitEquals(x + y, aa.get(i));
246         }
247       }
248     }
249   }
250 
251   /** getAndAccumulate with max stores max of given value to current, and returns previous value */
testGetAndAccumulateWithMax()252   public void testGetAndAccumulateWithMax() {
253     AtomicDoubleArray aa = new AtomicDoubleArray(SIZE);
254     for (int i : new int[] {0, SIZE - 1}) {
255       for (double x : VALUES) {
256         for (double y : VALUES) {
257           aa.set(i, x);
258           double z = aa.getAndAccumulate(i, y, Double::max);
259           double expectedMax = max(x, y);
260           assertBitEquals(x, z);
261           assertBitEquals(expectedMax, aa.get(i));
262         }
263       }
264     }
265   }
266 
267   /** accumulateAndGet with sum adds given value to current, and returns current value */
testAccumulateAndGetWithSum()268   public void testAccumulateAndGetWithSum() {
269     AtomicDoubleArray aa = new AtomicDoubleArray(SIZE);
270     for (int i : new int[] {0, SIZE - 1}) {
271       for (double x : VALUES) {
272         for (double y : VALUES) {
273           aa.set(i, x);
274           double z = aa.accumulateAndGet(i, y, Double::sum);
275           assertBitEquals(x + y, z);
276           assertBitEquals(x + y, aa.get(i));
277         }
278       }
279     }
280   }
281 
282   /** accumulateAndGet with max stores max of given value to current, and returns current value */
testAccumulateAndGetWithMax()283   public void testAccumulateAndGetWithMax() {
284     AtomicDoubleArray aa = new AtomicDoubleArray(SIZE);
285     for (int i : new int[] {0, SIZE - 1}) {
286       for (double x : VALUES) {
287         for (double y : VALUES) {
288           aa.set(i, x);
289           double z = aa.accumulateAndGet(i, y, Double::max);
290           double expectedMax = max(x, y);
291           assertBitEquals(expectedMax, z);
292           assertBitEquals(expectedMax, aa.get(i));
293         }
294       }
295     }
296   }
297 
298   /** getAndUpdate adds given value to current, and returns previous value */
testGetAndUpdateWithSum()299   public void testGetAndUpdateWithSum() {
300     AtomicDoubleArray aa = new AtomicDoubleArray(SIZE);
301     for (int i : new int[] {0, SIZE - 1}) {
302       for (double x : VALUES) {
303         for (double y : VALUES) {
304           aa.set(i, x);
305           double z = aa.getAndUpdate(i, value -> value + y);
306           assertBitEquals(x, z);
307           assertBitEquals(x + y, aa.get(i));
308         }
309       }
310     }
311   }
312 
313   /** getAndUpdate subtracts given value to current, and returns previous value */
testGetAndUpdateWithSubtract()314   public void testGetAndUpdateWithSubtract() {
315     AtomicDoubleArray aa = new AtomicDoubleArray(SIZE);
316     for (int i : new int[] {0, SIZE - 1}) {
317       for (double x : VALUES) {
318         for (double y : VALUES) {
319           aa.set(i, x);
320           double z = aa.getAndUpdate(i, value -> value - y);
321           assertBitEquals(x, z);
322           assertBitEquals(x - y, aa.get(i));
323         }
324       }
325     }
326   }
327 
328   /** updateAndGet adds given value to current, and returns current value */
testUpdateAndGetWithSum()329   public void testUpdateAndGetWithSum() {
330     AtomicDoubleArray aa = new AtomicDoubleArray(SIZE);
331     for (int i : new int[] {0, SIZE - 1}) {
332       for (double x : VALUES) {
333         for (double y : VALUES) {
334           aa.set(i, x);
335           double z = aa.updateAndGet(i, value -> value + y);
336           assertBitEquals(x + y, z);
337           assertBitEquals(x + y, aa.get(i));
338         }
339       }
340     }
341   }
342 
343   /** updateAndGet subtracts given value to current, and returns current value */
testUpdateAndGetWithSubtract()344   public void testUpdateAndGetWithSubtract() {
345     AtomicDoubleArray aa = new AtomicDoubleArray(SIZE);
346     for (int i : new int[] {0, SIZE - 1}) {
347       for (double x : VALUES) {
348         for (double y : VALUES) {
349           aa.set(i, x);
350           double z = aa.updateAndGet(i, value -> value - y);
351           assertBitEquals(x - y, z);
352           assertBitEquals(x - y, aa.get(i));
353         }
354       }
355     }
356   }
357 
358   static final long COUNTDOWN = 100000;
359 
360   class Counter extends CheckedRunnable {
361     final AtomicDoubleArray aa;
362     volatile long counts;
363 
Counter(AtomicDoubleArray a)364     Counter(AtomicDoubleArray a) {
365       aa = a;
366     }
367 
368     @Override
realRun()369     public void realRun() {
370       for (; ; ) {
371         boolean done = true;
372         for (int i = 0; i < aa.length(); i++) {
373           double v = aa.get(i);
374           assertTrue(v >= 0);
375           if (v != 0) {
376             done = false;
377             if (aa.compareAndSet(i, v, v - 1.0)) {
378               ++counts;
379             }
380           }
381         }
382         if (done) {
383           break;
384         }
385       }
386     }
387   }
388 
389   /**
390    * Multiple threads using same array of counters successfully update a number of times equal to
391    * total count
392    */
testCountingInMultipleThreads()393   public void testCountingInMultipleThreads() throws InterruptedException {
394     final AtomicDoubleArray aa = new AtomicDoubleArray(SIZE);
395     for (int i = 0; i < SIZE; i++) {
396       aa.set(i, (double) COUNTDOWN);
397     }
398     Counter c1 = new Counter(aa);
399     Counter c2 = new Counter(aa);
400     Thread t1 = newStartedThread(c1);
401     Thread t2 = newStartedThread(c2);
402     awaitTermination(t1);
403     awaitTermination(t2);
404     assertEquals(SIZE * COUNTDOWN, c1.counts + c2.counts);
405   }
406 
407   /** a deserialized serialized array holds same values */
testSerialization()408   public void testSerialization() throws Exception {
409     AtomicDoubleArray x = new AtomicDoubleArray(SIZE);
410     for (int i = 0; i < SIZE; i++) {
411       x.set(i, (double) -i);
412     }
413     AtomicDoubleArray y = serialClone(x);
414     assertTrue(x != y);
415     assertEquals(x.length(), y.length());
416     for (int i = 0; i < SIZE; i++) {
417       assertBitEquals(x.get(i), y.get(i));
418     }
419 
420     AtomicDoubleArray a = new AtomicDoubleArray(VALUES);
421     AtomicDoubleArray b = serialClone(a);
422     assertFalse(a.equals(b));
423     assertFalse(b.equals(a));
424     assertEquals(a.length(), b.length());
425     for (int i = 0; i < VALUES.length; i++) {
426       assertBitEquals(a.get(i), b.get(i));
427     }
428   }
429 
430   /** toString returns current value */
testToString()431   public void testToString() {
432     AtomicDoubleArray aa = new AtomicDoubleArray(VALUES);
433     assertEquals(Arrays.toString(VALUES), aa.toString());
434     assertEquals("[]", new AtomicDoubleArray(0).toString());
435     assertEquals("[]", new AtomicDoubleArray(new double[0]).toString());
436   }
437 
438   /** compareAndSet treats +0.0 and -0.0 as distinct values */
testDistinctZeros()439   public void testDistinctZeros() {
440     AtomicDoubleArray aa = new AtomicDoubleArray(SIZE);
441     for (int i : new int[] {0, SIZE - 1}) {
442       assertFalse(aa.compareAndSet(i, -0.0, 7.0));
443       assertFalse(aa.weakCompareAndSet(i, -0.0, 7.0));
444       assertBitEquals(+0.0, aa.get(i));
445       assertTrue(aa.compareAndSet(i, +0.0, -0.0));
446       assertBitEquals(-0.0, aa.get(i));
447       assertFalse(aa.compareAndSet(i, +0.0, 7.0));
448       assertFalse(aa.weakCompareAndSet(i, +0.0, 7.0));
449       assertBitEquals(-0.0, aa.get(i));
450     }
451   }
452 }
453