AtomicDoubleArrayTest.java revision 7dd252788645e940eada959bdde927426e2531c9
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
14package com.google.common.util.concurrent;
15
16import java.util.Arrays;
17
18/**
19 * Unit test for {@link AtomicDoubleArray}.
20 */
21public class AtomicDoubleArrayTest extends JSR166TestCase {
22
23  private static final double[] VALUES = {
24    Double.NEGATIVE_INFINITY,
25    -Double.MAX_VALUE,
26    Long.MIN_VALUE,
27    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    Integer.MAX_VALUE,
37    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 */
45  static boolean bitEquals(double x, double y) {
46    return Double.doubleToRawLongBits(x) == Double.doubleToRawLongBits(y);
47  }
48
49  static void assertBitEquals(double x, double y) {
50    assertEquals(Double.doubleToRawLongBits(x),
51                 Double.doubleToRawLongBits(y));
52  }
53
54  /**
55   * constructor creates array of given size with all elements zero
56   */
57  public void testConstructor() {
58    AtomicDoubleArray aa = new AtomicDoubleArray(SIZE);
59    for (int i = 0; i < SIZE; i++) {
60      assertBitEquals(0.0, aa.get(i));
61    }
62  }
63
64  /**
65   * constructor with null array throws NPE
66   */
67  public void testConstructor2NPE() {
68    try {
69      double[] a = null;
70      AtomicDoubleArray aa = new AtomicDoubleArray(a);
71      shouldThrow();
72    } catch (NullPointerException success) {}
73  }
74
75  /**
76   * constructor with array is of same size and has all elements
77   */
78  public void testConstructor2() {
79    AtomicDoubleArray aa = new AtomicDoubleArray(VALUES);
80    assertEquals(VALUES.length, aa.length());
81    for (int i = 0; i < VALUES.length; i++) {
82      assertBitEquals(VALUES[i], aa.get(i));
83    }
84  }
85
86  /**
87   * constructor with empty array has size 0 and contains no elements
88   */
89  public void testConstructorEmptyArray() {
90    AtomicDoubleArray aa = new AtomicDoubleArray(new double[0]);
91    assertEquals(0, aa.length());
92    try {
93      aa.get(0);
94      shouldThrow();
95    } catch (IndexOutOfBoundsException success) {}
96  }
97
98  /**
99   * constructor with length zero has size 0 and contains no elements
100   */
101  public void testConstructorZeroLength() {
102    AtomicDoubleArray aa = new AtomicDoubleArray(0);
103    assertEquals(0, aa.length());
104    try {
105      aa.get(0);
106      shouldThrow();
107    } catch (IndexOutOfBoundsException success) {}
108  }
109
110  /**
111   * get and set for out of bound indices throw IndexOutOfBoundsException
112   */
113  public void testIndexing() {
114    AtomicDoubleArray aa = new AtomicDoubleArray(SIZE);
115    for (int index : new int[] { -1, SIZE }) {
116      try {
117        aa.get(index);
118        shouldThrow();
119      } catch (IndexOutOfBoundsException success) {}
120      try {
121        aa.set(index, 1.0);
122        shouldThrow();
123      } catch (IndexOutOfBoundsException success) {}
124      try {
125        aa.lazySet(index, 1.0);
126        shouldThrow();
127      } catch (IndexOutOfBoundsException success) {}
128      try {
129        aa.compareAndSet(index, 1.0, 2.0);
130        shouldThrow();
131      } catch (IndexOutOfBoundsException success) {}
132      try {
133        aa.weakCompareAndSet(index, 1.0, 2.0);
134        shouldThrow();
135      } catch (IndexOutOfBoundsException success) {}
136      try {
137        aa.getAndAdd(index, 1.0);
138        shouldThrow();
139      } catch (IndexOutOfBoundsException success) {}
140      try {
141        aa.addAndGet(index, 1.0);
142        shouldThrow();
143      } catch (IndexOutOfBoundsException success) {}
144    }
145  }
146
147  /**
148   * get returns the last value set at index
149   */
150  public void testGetSet() {
151    AtomicDoubleArray aa = new AtomicDoubleArray(VALUES.length);
152    for (int i = 0; i < VALUES.length; i++) {
153      assertBitEquals(0.0, aa.get(i));
154      aa.set(i, VALUES[i]);
155      assertBitEquals(VALUES[i], aa.get(i));
156      aa.set(i, -3.0);
157      assertBitEquals(-3.0, aa.get(i));
158    }
159  }
160
161  /**
162   * get returns the last value lazySet at index by same thread
163   */
164  public void testGetLazySet() {
165    AtomicDoubleArray aa = new AtomicDoubleArray(VALUES.length);
166    for (int i = 0; i < VALUES.length; i++) {
167      assertBitEquals(0.0, aa.get(i));
168      aa.lazySet(i, VALUES[i]);
169      assertBitEquals(VALUES[i], aa.get(i));
170      aa.lazySet(i, -3.0);
171      assertBitEquals(-3.0, aa.get(i));
172    }
173  }
174
175  /**
176   * compareAndSet succeeds in changing value if equal to expected else fails
177   */
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  /**
195   * compareAndSet in one thread enables another waiting for value
196   * to succeed
197   */
198
199      public void testCompareAndSetInMultipleThreads() throws InterruptedException {
200    final AtomicDoubleArray a = new AtomicDoubleArray(1);
201    a.set(0, 1.0);
202    Thread t = newStartedThread(new CheckedRunnable() {
203        @Override
204        public void realRun() {
205          while (!a.compareAndSet(0, 2.0, 3.0)) {
206            Thread.yield();
207          }
208        }});
209
210    assertTrue(a.compareAndSet(0, 1.0, 2.0));
211    awaitTermination(t);
212    assertBitEquals(3.0, a.get(0));
213  }
214
215  /**
216   * repeated weakCompareAndSet succeeds in changing value when equal
217   * to expected
218   */
219  public void testWeakCompareAndSet() {
220    AtomicDoubleArray aa = new AtomicDoubleArray(SIZE);
221    for (int i : new int[] { 0, SIZE - 1}) {
222      double prev = 0.0;
223      double unused = Math.E + Math.PI;
224      for (double x : VALUES) {
225        assertBitEquals(prev, aa.get(i));
226        assertFalse(aa.weakCompareAndSet(i, unused, x));
227        assertBitEquals(prev, aa.get(i));
228        while (!aa.weakCompareAndSet(i, prev, x)) {
229          ;
230        }
231        assertBitEquals(x, aa.get(i));
232        prev = x;
233      }
234    }
235  }
236
237  /**
238   * getAndSet returns previous value and sets to given value at given index
239   */
240  public void testGetAndSet() {
241    AtomicDoubleArray aa = new AtomicDoubleArray(SIZE);
242    for (int i : new int[] { 0, SIZE - 1}) {
243      double prev = 0.0;
244      for (double x : VALUES) {
245        assertBitEquals(prev, aa.getAndSet(i, x));
246        prev = x;
247      }
248    }
249  }
250
251  /**
252   * getAndAdd returns previous value and adds given value
253   */
254  public void testGetAndAdd() {
255    AtomicDoubleArray aa = new AtomicDoubleArray(SIZE);
256    for (int i : new int[] { 0, SIZE - 1}) {
257      for (double x : VALUES) {
258        for (double y : VALUES) {
259          aa.set(i, x);
260          double z = aa.getAndAdd(i, y);
261          assertBitEquals(x, z);
262          assertBitEquals(x + y, aa.get(i));
263        }
264      }
265    }
266  }
267
268  /**
269   * addAndGet adds given value to current, and returns current value
270   */
271  public void testAddAndGet() {
272    AtomicDoubleArray aa = new AtomicDoubleArray(SIZE);
273    for (int i : new int[] { 0, SIZE - 1}) {
274      for (double x : VALUES) {
275        for (double y : VALUES) {
276          aa.set(i, x);
277          double z = aa.addAndGet(i, y);
278          assertBitEquals(x + y, z);
279          assertBitEquals(x + y, aa.get(i));
280        }
281      }
282    }
283  }
284
285  static final long COUNTDOWN = 100000;
286
287  class Counter extends CheckedRunnable {
288    final AtomicDoubleArray aa;
289    volatile long counts;
290    Counter(AtomicDoubleArray a) { aa = a; }
291    @Override
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, 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, -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}
383