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