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