• 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 org.junit.Assert.assertThrows;
17 
18 import java.util.Arrays;
19 
20 /** Unit test for {@link AtomicDoubleArray}. */
21 public class AtomicDoubleArrayTest extends JSR166TestCase {
22 
23   private static final double[] VALUES = {
24     Double.NEGATIVE_INFINITY,
25     -Double.MAX_VALUE,
26     (double) Long.MIN_VALUE,
27     (double) Integer.MIN_VALUE,
28     -Math.PI,
29     -1.0,
30     -Double.MIN_VALUE,
31     -0.0,
32     +0.0,
33     Double.MIN_VALUE,
34     1.0,
35     Math.PI,
36     (double) Integer.MAX_VALUE,
37     (double) Long.MAX_VALUE,
38     Double.MAX_VALUE,
39     Double.POSITIVE_INFINITY,
40     Double.NaN,
41     Float.MAX_VALUE,
42   };
43 
44   /** The notion of equality used by AtomicDoubleArray */
bitEquals(double x, double y)45   static boolean bitEquals(double x, double y) {
46     return Double.doubleToRawLongBits(x) == Double.doubleToRawLongBits(y);
47   }
48 
assertBitEquals(double x, double y)49   static void assertBitEquals(double x, double y) {
50     assertEquals(Double.doubleToRawLongBits(x), Double.doubleToRawLongBits(y));
51   }
52 
53   /** constructor creates array of given size with all elements zero */
testConstructor()54   public void testConstructor() {
55     AtomicDoubleArray aa = new AtomicDoubleArray(SIZE);
56     for (int i = 0; i < SIZE; i++) {
57       assertBitEquals(0.0, aa.get(i));
58     }
59   }
60 
61   /** constructor with null array throws NPE */
testConstructor2NPE()62   public void testConstructor2NPE() {
63     double[] a = null;
64     assertThrows(NullPointerException.class, () -> new AtomicDoubleArray(a));
65   }
66 
67   /** constructor with array is of same size and has all elements */
testConstructor2()68   public void testConstructor2() {
69     AtomicDoubleArray aa = new AtomicDoubleArray(VALUES);
70     assertEquals(VALUES.length, aa.length());
71     for (int i = 0; i < VALUES.length; i++) {
72       assertBitEquals(VALUES[i], aa.get(i));
73     }
74   }
75 
76   /** constructor with empty array has size 0 and contains no elements */
testConstructorEmptyArray()77   public void testConstructorEmptyArray() {
78     AtomicDoubleArray aa = new AtomicDoubleArray(new double[0]);
79     assertEquals(0, aa.length());
80     assertThrows(IndexOutOfBoundsException.class, () -> aa.get(0));
81   }
82 
83   /** constructor with length zero has size 0 and contains no elements */
testConstructorZeroLength()84   public void testConstructorZeroLength() {
85     AtomicDoubleArray aa = new AtomicDoubleArray(0);
86     assertEquals(0, aa.length());
87     assertThrows(IndexOutOfBoundsException.class, () -> aa.get(0));
88   }
89 
90   /** get and set for out of bound indices throw IndexOutOfBoundsException */
testIndexing()91   public void testIndexing() {
92     AtomicDoubleArray aa = new AtomicDoubleArray(SIZE);
93     for (int index : new int[] {-1, SIZE}) {
94       assertThrows(IndexOutOfBoundsException.class, () -> aa.get(index));
95       assertThrows(IndexOutOfBoundsException.class, () -> aa.set(index, 1.0));
96       assertThrows(IndexOutOfBoundsException.class, () -> aa.lazySet(index, 1.0));
97       assertThrows(IndexOutOfBoundsException.class, () -> aa.compareAndSet(index, 1.0, 2.0));
98       assertThrows(IndexOutOfBoundsException.class, () -> aa.weakCompareAndSet(index, 1.0, 2.0));
99       assertThrows(IndexOutOfBoundsException.class, () -> aa.getAndAdd(index, 1.0));
100       assertThrows(IndexOutOfBoundsException.class, () -> aa.addAndGet(index, 1.0));
101     }
102   }
103 
104   /** get returns the last value set at index */
testGetSet()105   public void testGetSet() {
106     AtomicDoubleArray aa = new AtomicDoubleArray(VALUES.length);
107     for (int i = 0; i < VALUES.length; i++) {
108       assertBitEquals(0.0, aa.get(i));
109       aa.set(i, VALUES[i]);
110       assertBitEquals(VALUES[i], aa.get(i));
111       aa.set(i, -3.0);
112       assertBitEquals(-3.0, aa.get(i));
113     }
114   }
115 
116   /** get returns the last value lazySet at index by same thread */
testGetLazySet()117   public void testGetLazySet() {
118     AtomicDoubleArray aa = new AtomicDoubleArray(VALUES.length);
119     for (int i = 0; i < VALUES.length; i++) {
120       assertBitEquals(0.0, aa.get(i));
121       aa.lazySet(i, VALUES[i]);
122       assertBitEquals(VALUES[i], aa.get(i));
123       aa.lazySet(i, -3.0);
124       assertBitEquals(-3.0, aa.get(i));
125     }
126   }
127 
128   /** compareAndSet succeeds in changing value if equal to expected else fails */
testCompareAndSet()129   public void testCompareAndSet() {
130     AtomicDoubleArray aa = new AtomicDoubleArray(SIZE);
131     for (int i : new int[] {0, SIZE - 1}) {
132       double prev = 0.0;
133       double unused = Math.E + Math.PI;
134       for (double x : VALUES) {
135         assertBitEquals(prev, aa.get(i));
136         assertFalse(aa.compareAndSet(i, unused, x));
137         assertBitEquals(prev, aa.get(i));
138         assertTrue(aa.compareAndSet(i, prev, x));
139         assertBitEquals(x, aa.get(i));
140         prev = x;
141       }
142     }
143   }
144 
145   /** compareAndSet in one thread enables another waiting for value to succeed */
testCompareAndSetInMultipleThreads()146   public void testCompareAndSetInMultipleThreads() throws InterruptedException {
147     final AtomicDoubleArray a = new AtomicDoubleArray(1);
148     a.set(0, 1.0);
149     Thread t =
150         newStartedThread(
151             new CheckedRunnable() {
152               public void realRun() {
153                 while (!a.compareAndSet(0, 2.0, 3.0)) {
154                   Thread.yield();
155                 }
156               }
157             });
158 
159     assertTrue(a.compareAndSet(0, 1.0, 2.0));
160     awaitTermination(t);
161     assertBitEquals(3.0, a.get(0));
162   }
163 
164   /** repeated weakCompareAndSet succeeds in changing value when equal to expected */
testWeakCompareAndSet()165   public void testWeakCompareAndSet() {
166     AtomicDoubleArray aa = new AtomicDoubleArray(SIZE);
167     for (int i : new int[] {0, SIZE - 1}) {
168       double prev = 0.0;
169       double unused = Math.E + Math.PI;
170       for (double x : VALUES) {
171         assertBitEquals(prev, aa.get(i));
172         assertFalse(aa.weakCompareAndSet(i, unused, x));
173         assertBitEquals(prev, aa.get(i));
174         while (!aa.weakCompareAndSet(i, prev, x)) {;
175         }
176         assertBitEquals(x, aa.get(i));
177         prev = x;
178       }
179     }
180   }
181 
182   /** getAndSet returns previous value and sets to given value at given index */
testGetAndSet()183   public void testGetAndSet() {
184     AtomicDoubleArray aa = new AtomicDoubleArray(SIZE);
185     for (int i : new int[] {0, SIZE - 1}) {
186       double prev = 0.0;
187       for (double x : VALUES) {
188         assertBitEquals(prev, aa.getAndSet(i, x));
189         prev = x;
190       }
191     }
192   }
193 
194   /** getAndAdd returns previous value and adds given value */
testGetAndAdd()195   public void testGetAndAdd() {
196     AtomicDoubleArray aa = new AtomicDoubleArray(SIZE);
197     for (int i : new int[] {0, SIZE - 1}) {
198       for (double x : VALUES) {
199         for (double y : VALUES) {
200           aa.set(i, x);
201           double z = aa.getAndAdd(i, y);
202           assertBitEquals(x, z);
203           assertBitEquals(x + y, aa.get(i));
204         }
205       }
206     }
207   }
208 
209   /** addAndGet adds given value to current, and returns current value */
testAddAndGet()210   public void testAddAndGet() {
211     AtomicDoubleArray aa = new AtomicDoubleArray(SIZE);
212     for (int i : new int[] {0, SIZE - 1}) {
213       for (double x : VALUES) {
214         for (double y : VALUES) {
215           aa.set(i, x);
216           double z = aa.addAndGet(i, y);
217           assertBitEquals(x + y, z);
218           assertBitEquals(x + y, aa.get(i));
219         }
220       }
221     }
222   }
223 
224   static final long COUNTDOWN = 100000;
225 
226   class Counter extends CheckedRunnable {
227     final AtomicDoubleArray aa;
228     volatile long counts;
229 
Counter(AtomicDoubleArray a)230     Counter(AtomicDoubleArray a) {
231       aa = a;
232     }
233 
realRun()234     public void realRun() {
235       for (; ; ) {
236         boolean done = true;
237         for (int i = 0; i < aa.length(); i++) {
238           double v = aa.get(i);
239           assertTrue(v >= 0);
240           if (v != 0) {
241             done = false;
242             if (aa.compareAndSet(i, v, v - 1.0)) {
243               ++counts;
244             }
245           }
246         }
247         if (done) {
248           break;
249         }
250       }
251     }
252   }
253 
254   /**
255    * Multiple threads using same array of counters successfully update a number of times equal to
256    * total count
257    */
testCountingInMultipleThreads()258   public void testCountingInMultipleThreads() throws InterruptedException {
259     final AtomicDoubleArray aa = new AtomicDoubleArray(SIZE);
260     for (int i = 0; i < SIZE; i++) {
261       aa.set(i, (double) COUNTDOWN);
262     }
263     Counter c1 = new Counter(aa);
264     Counter c2 = new Counter(aa);
265     Thread t1 = newStartedThread(c1);
266     Thread t2 = newStartedThread(c2);
267     awaitTermination(t1);
268     awaitTermination(t2);
269     assertEquals(SIZE * COUNTDOWN, c1.counts + c2.counts);
270   }
271 
272   /** a deserialized serialized array holds same values */
testSerialization()273   public void testSerialization() throws Exception {
274     AtomicDoubleArray x = new AtomicDoubleArray(SIZE);
275     for (int i = 0; i < SIZE; i++) {
276       x.set(i, (double) -i);
277     }
278     AtomicDoubleArray y = serialClone(x);
279     assertTrue(x != y);
280     assertEquals(x.length(), y.length());
281     for (int i = 0; i < SIZE; i++) {
282       assertBitEquals(x.get(i), y.get(i));
283     }
284 
285     AtomicDoubleArray a = new AtomicDoubleArray(VALUES);
286     AtomicDoubleArray b = serialClone(a);
287     assertFalse(a.equals(b));
288     assertFalse(b.equals(a));
289     assertEquals(a.length(), b.length());
290     for (int i = 0; i < VALUES.length; i++) {
291       assertBitEquals(a.get(i), b.get(i));
292     }
293   }
294 
295   /** toString returns current value */
testToString()296   public void testToString() {
297     AtomicDoubleArray aa = new AtomicDoubleArray(VALUES);
298     assertEquals(Arrays.toString(VALUES), aa.toString());
299     assertEquals("[]", new AtomicDoubleArray(0).toString());
300     assertEquals("[]", new AtomicDoubleArray(new double[0]).toString());
301   }
302 
303   /** compareAndSet treats +0.0 and -0.0 as distinct values */
testDistinctZeros()304   public void testDistinctZeros() {
305     AtomicDoubleArray aa = new AtomicDoubleArray(SIZE);
306     for (int i : new int[] {0, SIZE - 1}) {
307       assertFalse(aa.compareAndSet(i, -0.0, 7.0));
308       assertFalse(aa.weakCompareAndSet(i, -0.0, 7.0));
309       assertBitEquals(+0.0, aa.get(i));
310       assertTrue(aa.compareAndSet(i, +0.0, -0.0));
311       assertBitEquals(-0.0, aa.get(i));
312       assertFalse(aa.compareAndSet(i, +0.0, 7.0));
313       assertFalse(aa.weakCompareAndSet(i, +0.0, 7.0));
314       assertBitEquals(-0.0, aa.get(i));
315     }
316   }
317 }
318