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