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