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 import java.util.Arrays;
     18 
     19 /**
     20  * Unit test for {@link AtomicDoubleArray}.
     21  */
     22 public 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