Home | History | Annotate | Download | only in concurrent
      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 }
    383