• 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 */
testCompareAndSetInMultipleThreads()184   public void testCompareAndSetInMultipleThreads() throws InterruptedException {
185     final AtomicDoubleArray a = new AtomicDoubleArray(1);
186     a.set(0, 1.0);
187     Thread t =
188         newStartedThread(
189             new CheckedRunnable() {
190               public void realRun() {
191                 while (!a.compareAndSet(0, 2.0, 3.0)) {
192                   Thread.yield();
193                 }
194               }
195             });
196 
197     assertTrue(a.compareAndSet(0, 1.0, 2.0));
198     awaitTermination(t);
199     assertBitEquals(3.0, a.get(0));
200   }
201 
202   /** repeated weakCompareAndSet succeeds in changing value when equal to expected */
testWeakCompareAndSet()203   public void testWeakCompareAndSet() {
204     AtomicDoubleArray aa = new AtomicDoubleArray(SIZE);
205     for (int i : new int[] {0, SIZE - 1}) {
206       double prev = 0.0;
207       double unused = Math.E + Math.PI;
208       for (double x : VALUES) {
209         assertBitEquals(prev, aa.get(i));
210         assertFalse(aa.weakCompareAndSet(i, unused, x));
211         assertBitEquals(prev, aa.get(i));
212         while (!aa.weakCompareAndSet(i, prev, x)) {;
213         }
214         assertBitEquals(x, aa.get(i));
215         prev = x;
216       }
217     }
218   }
219 
220   /** getAndSet returns previous value and sets to given value at given index */
testGetAndSet()221   public void testGetAndSet() {
222     AtomicDoubleArray aa = new AtomicDoubleArray(SIZE);
223     for (int i : new int[] {0, SIZE - 1}) {
224       double prev = 0.0;
225       for (double x : VALUES) {
226         assertBitEquals(prev, aa.getAndSet(i, x));
227         prev = x;
228       }
229     }
230   }
231 
232   /** getAndAdd returns previous value and adds given value */
testGetAndAdd()233   public void testGetAndAdd() {
234     AtomicDoubleArray aa = new AtomicDoubleArray(SIZE);
235     for (int i : new int[] {0, SIZE - 1}) {
236       for (double x : VALUES) {
237         for (double y : VALUES) {
238           aa.set(i, x);
239           double z = aa.getAndAdd(i, y);
240           assertBitEquals(x, z);
241           assertBitEquals(x + y, aa.get(i));
242         }
243       }
244     }
245   }
246 
247   /** addAndGet adds given value to current, and returns current value */
testAddAndGet()248   public void testAddAndGet() {
249     AtomicDoubleArray aa = new AtomicDoubleArray(SIZE);
250     for (int i : new int[] {0, SIZE - 1}) {
251       for (double x : VALUES) {
252         for (double y : VALUES) {
253           aa.set(i, x);
254           double z = aa.addAndGet(i, y);
255           assertBitEquals(x + y, z);
256           assertBitEquals(x + y, aa.get(i));
257         }
258       }
259     }
260   }
261 
262   static final long COUNTDOWN = 100000;
263 
264   class Counter extends CheckedRunnable {
265     final AtomicDoubleArray aa;
266     volatile long counts;
267 
Counter(AtomicDoubleArray a)268     Counter(AtomicDoubleArray a) {
269       aa = a;
270     }
271 
realRun()272     public void realRun() {
273       for (; ; ) {
274         boolean done = true;
275         for (int i = 0; i < aa.length(); i++) {
276           double v = aa.get(i);
277           assertTrue(v >= 0);
278           if (v != 0) {
279             done = false;
280             if (aa.compareAndSet(i, v, v - 1.0)) {
281               ++counts;
282             }
283           }
284         }
285         if (done) {
286           break;
287         }
288       }
289     }
290   }
291 
292   /**
293    * Multiple threads using same array of counters successfully update a number of times equal to
294    * total count
295    */
testCountingInMultipleThreads()296   public void testCountingInMultipleThreads() throws InterruptedException {
297     final AtomicDoubleArray aa = new AtomicDoubleArray(SIZE);
298     for (int i = 0; i < SIZE; i++) {
299       aa.set(i, (double) COUNTDOWN);
300     }
301     Counter c1 = new Counter(aa);
302     Counter c2 = new Counter(aa);
303     Thread t1 = newStartedThread(c1);
304     Thread t2 = newStartedThread(c2);
305     awaitTermination(t1);
306     awaitTermination(t2);
307     assertEquals(SIZE * COUNTDOWN, c1.counts + c2.counts);
308   }
309 
310   /** a deserialized serialized array holds same values */
testSerialization()311   public void testSerialization() throws Exception {
312     AtomicDoubleArray x = new AtomicDoubleArray(SIZE);
313     for (int i = 0; i < SIZE; i++) {
314       x.set(i, (double) -i);
315     }
316     AtomicDoubleArray y = serialClone(x);
317     assertTrue(x != y);
318     assertEquals(x.length(), y.length());
319     for (int i = 0; i < SIZE; i++) {
320       assertBitEquals(x.get(i), y.get(i));
321     }
322 
323     AtomicDoubleArray a = new AtomicDoubleArray(VALUES);
324     AtomicDoubleArray b = serialClone(a);
325     assertFalse(a.equals(b));
326     assertFalse(b.equals(a));
327     assertEquals(a.length(), b.length());
328     for (int i = 0; i < VALUES.length; i++) {
329       assertBitEquals(a.get(i), b.get(i));
330     }
331   }
332 
333   /** toString returns current value */
testToString()334   public void testToString() {
335     AtomicDoubleArray aa = new AtomicDoubleArray(VALUES);
336     assertEquals(Arrays.toString(VALUES), aa.toString());
337     assertEquals("[]", new AtomicDoubleArray(0).toString());
338     assertEquals("[]", new AtomicDoubleArray(new double[0]).toString());
339   }
340 
341   /** compareAndSet treats +0.0 and -0.0 as distinct values */
testDistinctZeros()342   public void testDistinctZeros() {
343     AtomicDoubleArray aa = new AtomicDoubleArray(SIZE);
344     for (int i : new int[] {0, SIZE - 1}) {
345       assertFalse(aa.compareAndSet(i, -0.0, 7.0));
346       assertFalse(aa.weakCompareAndSet(i, -0.0, 7.0));
347       assertBitEquals(+0.0, aa.get(i));
348       assertTrue(aa.compareAndSet(i, +0.0, -0.0));
349       assertBitEquals(-0.0, aa.get(i));
350       assertFalse(aa.compareAndSet(i, +0.0, 7.0));
351       assertFalse(aa.weakCompareAndSet(i, +0.0, 7.0));
352       assertBitEquals(-0.0, aa.get(i));
353     }
354   }
355 }
356