AtomicDoubleArrayTest.java revision 1d580d0f6ee4f21eb309ba7b509d2c6d671c4044
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 junit.framework.*;
17import java.util.Arrays;
18
19/**
20 * Unit test for {@link AtomicDoubleArray}.
21 */
22public class AtomicDoubleArrayTest extends JSR166TestCase {
23
24  private static final double[] VALUES = {
25    Double.NEGATIVE_INFINITY,
26    -Double.MAX_VALUE,
27    (double) Long.MIN_VALUE,
28    (double) Integer.MIN_VALUE,
29    -Math.PI,
30    -1.0,
31    -Double.MIN_VALUE,
32    -0.0,
33    +0.0,
34    Double.MIN_VALUE,
35    1.0,
36    Math.PI,
37    (double) Integer.MAX_VALUE,
38    (double) Long.MAX_VALUE,
39    Double.MAX_VALUE,
40    Double.POSITIVE_INFINITY,
41    Double.NaN,
42    Float.MAX_VALUE,
43  };
44
45  /** The notion of equality used by AtomicDoubleArray */
46  static boolean bitEquals(double x, double y) {
47    return Double.doubleToRawLongBits(x) == Double.doubleToRawLongBits(y);
48  }
49
50  static void assertBitEquals(double x, double y) {
51    assertEquals(Double.doubleToRawLongBits(x),
52                 Double.doubleToRawLongBits(y));
53  }
54
55  /**
56   * constructor creates array of given size with all elements zero
57   */
58  public void testConstructor() {
59    AtomicDoubleArray aa = new AtomicDoubleArray(SIZE);
60    for (int i = 0; i < SIZE; i++) {
61      assertBitEquals(0.0, aa.get(i));
62    }
63  }
64
65  /**
66   * constructor with null array throws NPE
67   */
68  public void testConstructor2NPE() {
69    try {
70      double[] a = null;
71      AtomicDoubleArray aa = new AtomicDoubleArray(a);
72      shouldThrow();
73    } catch (NullPointerException success) {}
74  }
75
76  /**
77   * constructor with array is of same size and has all elements
78   */
79  public void testConstructor2() {
80    AtomicDoubleArray aa = new AtomicDoubleArray(VALUES);
81    assertEquals(VALUES.length, aa.length());
82    for (int i = 0; i < VALUES.length; i++) {
83      assertBitEquals(VALUES[i], aa.get(i));
84    }
85  }
86
87  /**
88   * constructor with empty array has size 0 and contains no elements
89   */
90  public void testConstructorEmptyArray() {
91    AtomicDoubleArray aa = new AtomicDoubleArray(new double[0]);
92    assertEquals(0, aa.length());
93    try {
94      aa.get(0);
95      shouldThrow();
96    } catch (IndexOutOfBoundsException success) {}
97  }
98
99  /**
100   * constructor with length zero has size 0 and contains no elements
101   */
102  public void testConstructorZeroLength() {
103    AtomicDoubleArray aa = new AtomicDoubleArray(0);
104    assertEquals(0, aa.length());
105    try {
106      aa.get(0);
107      shouldThrow();
108    } catch (IndexOutOfBoundsException success) {}
109  }
110
111  /**
112   * get and set for out of bound indices throw IndexOutOfBoundsException
113   */
114  public void testIndexing() {
115    AtomicDoubleArray aa = new AtomicDoubleArray(SIZE);
116    for (int index : new int[] { -1, SIZE }) {
117      try {
118        aa.get(index);
119        shouldThrow();
120      } catch (IndexOutOfBoundsException success) {}
121      try {
122        aa.set(index, 1.0);
123        shouldThrow();
124      } catch (IndexOutOfBoundsException success) {}
125      try {
126        aa.lazySet(index, 1.0);
127        shouldThrow();
128      } catch (IndexOutOfBoundsException success) {}
129      try {
130        aa.compareAndSet(index, 1.0, 2.0);
131        shouldThrow();
132      } catch (IndexOutOfBoundsException success) {}
133      try {
134        aa.weakCompareAndSet(index, 1.0, 2.0);
135        shouldThrow();
136      } catch (IndexOutOfBoundsException success) {}
137      try {
138        aa.getAndAdd(index, 1.0);
139        shouldThrow();
140      } catch (IndexOutOfBoundsException success) {}
141      try {
142        aa.addAndGet(index, 1.0);
143        shouldThrow();
144      } catch (IndexOutOfBoundsException success) {}
145    }
146  }
147
148  /**
149   * get returns the last value set at index
150   */
151  public void testGetSet() {
152    AtomicDoubleArray aa = new AtomicDoubleArray(VALUES.length);
153    for (int i = 0; i < VALUES.length; i++) {
154      assertBitEquals(0.0, aa.get(i));
155      aa.set(i, VALUES[i]);
156      assertBitEquals(VALUES[i], aa.get(i));
157      aa.set(i, -3.0);
158      assertBitEquals(-3.0, aa.get(i));
159    }
160  }
161
162  /**
163   * get returns the last value lazySet at index by same thread
164   */
165  public void testGetLazySet() {
166    AtomicDoubleArray aa = new AtomicDoubleArray(VALUES.length);
167    for (int i = 0; i < VALUES.length; i++) {
168      assertBitEquals(0.0, aa.get(i));
169      aa.lazySet(i, VALUES[i]);
170      assertBitEquals(VALUES[i], aa.get(i));
171      aa.lazySet(i, -3.0);
172      assertBitEquals(-3.0, aa.get(i));
173    }
174  }
175
176  /**
177   * compareAndSet succeeds in changing value if equal to expected else fails
178   */
179  public void testCompareAndSet() {
180    AtomicDoubleArray aa = new AtomicDoubleArray(SIZE);
181    for (int i : new int[] { 0, SIZE - 1}) {
182      double prev = 0.0;
183      double unused = Math.E + Math.PI;
184      for (double x : VALUES) {
185        assertBitEquals(prev, aa.get(i));
186        assertFalse(aa.compareAndSet(i, unused, x));
187        assertBitEquals(prev, aa.get(i));
188        assertTrue(aa.compareAndSet(i, prev, x));
189        assertBitEquals(x, aa.get(i));
190        prev = x;
191      }
192    }
193  }
194
195  /**
196   * compareAndSet in one thread enables another waiting for value
197   * to succeed
198   */
199
200      public void testCompareAndSetInMultipleThreads() throws InterruptedException {
201    final AtomicDoubleArray a = new AtomicDoubleArray(1);
202    a.set(0, 1.0);
203    Thread t = newStartedThread(new CheckedRunnable() {
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    public void realRun() {
292      for (;;) {
293        boolean done = true;
294        for (int i = 0; i < aa.length(); i++) {
295          double v = aa.get(i);
296          assertTrue(v >= 0);
297          if (v != 0) {
298            done = false;
299            if (aa.compareAndSet(i, v, v - 1.0)) {
300              ++counts;
301            }
302          }
303        }
304        if (done) {
305          break;
306        }
307      }
308    }
309  }
310
311  /**
312   * Multiple threads using same array of counters successfully
313   * update a number of times equal to total count
314   */
315
316      public void testCountingInMultipleThreads() throws InterruptedException {
317    final AtomicDoubleArray aa = new AtomicDoubleArray(SIZE);
318    for (int i = 0; i < SIZE; i++) {
319      aa.set(i, (double) COUNTDOWN);
320    }
321    Counter c1 = new Counter(aa);
322    Counter c2 = new Counter(aa);
323    Thread t1 = newStartedThread(c1);
324    Thread t2 = newStartedThread(c2);
325    awaitTermination(t1);
326    awaitTermination(t2);
327    assertEquals(c1.counts + c2.counts, SIZE * COUNTDOWN);
328  }
329
330  /**
331   * a deserialized serialized array holds same values
332   */
333  public void testSerialization() throws Exception {
334    AtomicDoubleArray x = new AtomicDoubleArray(SIZE);
335    for (int i = 0; i < SIZE; i++) {
336      x.set(i, (double) -i);
337    }
338    AtomicDoubleArray y = serialClone(x);
339    assertTrue(x != y);
340    assertEquals(x.length(), y.length());
341    for (int i = 0; i < SIZE; i++) {
342      assertBitEquals(x.get(i), y.get(i));
343    }
344
345    AtomicDoubleArray a = new AtomicDoubleArray(VALUES);
346    AtomicDoubleArray b = serialClone(a);
347    assertFalse(a.equals(b));
348    assertFalse(b.equals(a));
349    assertEquals(a.length(), b.length());
350    for (int i = 0; i < VALUES.length; i++) {
351      assertBitEquals(a.get(i), b.get(i));
352    }
353  }
354
355  /**
356   * toString returns current value
357   */
358  public void testToString() {
359    AtomicDoubleArray aa = new AtomicDoubleArray(VALUES);
360    assertEquals(Arrays.toString(VALUES), aa.toString());
361    assertEquals("[]", new AtomicDoubleArray(0).toString());
362    assertEquals("[]", new AtomicDoubleArray(new double[0]).toString());
363  }
364
365  /**
366   * compareAndSet treats +0.0 and -0.0 as distinct values
367   */
368  public void testDistinctZeros() {
369    AtomicDoubleArray aa = new AtomicDoubleArray(SIZE);
370    for (int i : new int[] { 0, SIZE - 1}) {
371      assertFalse(aa.compareAndSet(i, -0.0, 7.0));
372      assertFalse(aa.weakCompareAndSet(i, -0.0, 7.0));
373      assertBitEquals(+0.0, aa.get(i));
374      assertTrue(aa.compareAndSet(i, +0.0, -0.0));
375      assertBitEquals(-0.0, aa.get(i));
376      assertFalse(aa.compareAndSet(i, +0.0, 7.0));
377      assertFalse(aa.weakCompareAndSet(i, +0.0, 7.0));
378      assertBitEquals(-0.0, aa.get(i));
379    }
380  }
381}
382