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 java.lang.Math.max; 17 import static org.junit.Assert.assertThrows; 18 19 import com.google.common.annotations.GwtIncompatible; 20 import com.google.common.testing.NullPointerTester; 21 import java.util.Arrays; 22 23 /** Unit test for {@link AtomicDoubleArray}. */ 24 public class AtomicDoubleArrayTest extends JSR166TestCase { 25 26 private static final double[] VALUES = { 27 Double.NEGATIVE_INFINITY, 28 -Double.MAX_VALUE, 29 (double) Long.MIN_VALUE, 30 (double) Integer.MIN_VALUE, 31 -Math.PI, 32 -1.0, 33 -Double.MIN_VALUE, 34 -0.0, 35 +0.0, 36 Double.MIN_VALUE, 37 1.0, 38 Math.PI, 39 (double) Integer.MAX_VALUE, 40 (double) Long.MAX_VALUE, 41 Double.MAX_VALUE, 42 Double.POSITIVE_INFINITY, 43 Double.NaN, 44 Float.MAX_VALUE, 45 }; 46 47 /** The notion of equality used by AtomicDoubleArray */ bitEquals(double x, double y)48 static boolean bitEquals(double x, double y) { 49 return Double.doubleToRawLongBits(x) == Double.doubleToRawLongBits(y); 50 } 51 assertBitEquals(double x, double y)52 static void assertBitEquals(double x, double y) { 53 assertEquals(Double.doubleToRawLongBits(x), Double.doubleToRawLongBits(y)); 54 } 55 56 @GwtIncompatible // NullPointerTester testNulls()57 public void testNulls() { 58 new NullPointerTester().testAllPublicStaticMethods(AtomicDoubleArray.class); 59 new NullPointerTester().testAllPublicConstructors(AtomicDoubleArray.class); 60 new NullPointerTester().testAllPublicInstanceMethods(new AtomicDoubleArray(1)); 61 } 62 63 /** constructor creates array of given size with all elements zero */ testConstructor()64 public void testConstructor() { 65 AtomicDoubleArray aa = new AtomicDoubleArray(SIZE); 66 for (int i = 0; i < SIZE; i++) { 67 assertBitEquals(0.0, aa.get(i)); 68 } 69 } 70 71 /** constructor with null array throws NPE */ testConstructor2NPE()72 public void testConstructor2NPE() { 73 double[] a = null; 74 assertThrows(NullPointerException.class, () -> new AtomicDoubleArray(a)); 75 } 76 77 /** constructor with array is of same size and has all elements */ testConstructor2()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 /** constructor with empty array has size 0 and contains no elements */ testConstructorEmptyArray()87 public void testConstructorEmptyArray() { 88 AtomicDoubleArray aa = new AtomicDoubleArray(new double[0]); 89 assertEquals(0, aa.length()); 90 assertThrows(IndexOutOfBoundsException.class, () -> aa.get(0)); 91 } 92 93 /** constructor with length zero has size 0 and contains no elements */ testConstructorZeroLength()94 public void testConstructorZeroLength() { 95 AtomicDoubleArray aa = new AtomicDoubleArray(0); 96 assertEquals(0, aa.length()); 97 assertThrows(IndexOutOfBoundsException.class, () -> aa.get(0)); 98 } 99 100 /** get and set for out of bound indices throw IndexOutOfBoundsException */ testIndexing()101 public void testIndexing() { 102 AtomicDoubleArray aa = new AtomicDoubleArray(SIZE); 103 for (int index : new int[] {-1, SIZE}) { 104 assertThrows(IndexOutOfBoundsException.class, () -> aa.get(index)); 105 assertThrows(IndexOutOfBoundsException.class, () -> aa.set(index, 1.0)); 106 assertThrows(IndexOutOfBoundsException.class, () -> aa.lazySet(index, 1.0)); 107 assertThrows(IndexOutOfBoundsException.class, () -> aa.compareAndSet(index, 1.0, 2.0)); 108 assertThrows(IndexOutOfBoundsException.class, () -> aa.weakCompareAndSet(index, 1.0, 2.0)); 109 assertThrows(IndexOutOfBoundsException.class, () -> aa.getAndAdd(index, 1.0)); 110 assertThrows(IndexOutOfBoundsException.class, () -> aa.addAndGet(index, 1.0)); 111 } 112 } 113 114 /** get returns the last value set at index */ testGetSet()115 public void testGetSet() { 116 AtomicDoubleArray aa = new AtomicDoubleArray(VALUES.length); 117 for (int i = 0; i < VALUES.length; i++) { 118 assertBitEquals(0.0, aa.get(i)); 119 aa.set(i, VALUES[i]); 120 assertBitEquals(VALUES[i], aa.get(i)); 121 aa.set(i, -3.0); 122 assertBitEquals(-3.0, aa.get(i)); 123 } 124 } 125 126 /** get returns the last value lazySet at index by same thread */ testGetLazySet()127 public void testGetLazySet() { 128 AtomicDoubleArray aa = new AtomicDoubleArray(VALUES.length); 129 for (int i = 0; i < VALUES.length; i++) { 130 assertBitEquals(0.0, aa.get(i)); 131 aa.lazySet(i, VALUES[i]); 132 assertBitEquals(VALUES[i], aa.get(i)); 133 aa.lazySet(i, -3.0); 134 assertBitEquals(-3.0, aa.get(i)); 135 } 136 } 137 138 /** compareAndSet succeeds in changing value if equal to expected else fails */ testCompareAndSet()139 public void testCompareAndSet() { 140 AtomicDoubleArray aa = new AtomicDoubleArray(SIZE); 141 for (int i : new int[] {0, SIZE - 1}) { 142 double prev = 0.0; 143 double unused = Math.E + Math.PI; 144 for (double x : VALUES) { 145 assertBitEquals(prev, aa.get(i)); 146 assertFalse(aa.compareAndSet(i, unused, x)); 147 assertBitEquals(prev, aa.get(i)); 148 assertTrue(aa.compareAndSet(i, prev, x)); 149 assertBitEquals(x, aa.get(i)); 150 prev = x; 151 } 152 } 153 } 154 155 /** compareAndSet in one thread enables another waiting for value to succeed */ testCompareAndSetInMultipleThreads()156 public void testCompareAndSetInMultipleThreads() throws InterruptedException { 157 final AtomicDoubleArray a = new AtomicDoubleArray(1); 158 a.set(0, 1.0); 159 Thread t = 160 newStartedThread( 161 new CheckedRunnable() { 162 @Override 163 public void realRun() { 164 while (!a.compareAndSet(0, 2.0, 3.0)) { 165 Thread.yield(); 166 } 167 } 168 }); 169 170 assertTrue(a.compareAndSet(0, 1.0, 2.0)); 171 awaitTermination(t); 172 assertBitEquals(3.0, a.get(0)); 173 } 174 175 /** repeated weakCompareAndSet succeeds in changing value when equal to expected */ testWeakCompareAndSet()176 public void testWeakCompareAndSet() { 177 AtomicDoubleArray aa = new AtomicDoubleArray(SIZE); 178 for (int i : new int[] {0, SIZE - 1}) { 179 double prev = 0.0; 180 double unused = Math.E + Math.PI; 181 for (double x : VALUES) { 182 assertBitEquals(prev, aa.get(i)); 183 assertFalse(aa.weakCompareAndSet(i, unused, x)); 184 assertBitEquals(prev, aa.get(i)); 185 while (!aa.weakCompareAndSet(i, prev, x)) { 186 ; 187 } 188 assertBitEquals(x, aa.get(i)); 189 prev = x; 190 } 191 } 192 } 193 194 /** getAndSet returns previous value and sets to given value at given index */ testGetAndSet()195 public void testGetAndSet() { 196 AtomicDoubleArray aa = new AtomicDoubleArray(SIZE); 197 for (int i : new int[] {0, SIZE - 1}) { 198 double prev = 0.0; 199 for (double x : VALUES) { 200 assertBitEquals(prev, aa.getAndSet(i, x)); 201 prev = x; 202 } 203 } 204 } 205 206 /** getAndAdd returns previous value and adds given value */ testGetAndAdd()207 public void testGetAndAdd() { 208 AtomicDoubleArray aa = new AtomicDoubleArray(SIZE); 209 for (int i : new int[] {0, SIZE - 1}) { 210 for (double x : VALUES) { 211 for (double y : VALUES) { 212 aa.set(i, x); 213 double z = aa.getAndAdd(i, y); 214 assertBitEquals(x, z); 215 assertBitEquals(x + y, aa.get(i)); 216 } 217 } 218 } 219 } 220 221 /** addAndGet adds given value to current, and returns current value */ testAddAndGet()222 public void testAddAndGet() { 223 AtomicDoubleArray aa = new AtomicDoubleArray(SIZE); 224 for (int i : new int[] {0, SIZE - 1}) { 225 for (double x : VALUES) { 226 for (double y : VALUES) { 227 aa.set(i, x); 228 double z = aa.addAndGet(i, y); 229 assertBitEquals(x + y, z); 230 assertBitEquals(x + y, aa.get(i)); 231 } 232 } 233 } 234 } 235 236 /** getAndAccumulate with sum adds given value to current, and returns previous value */ testGetAndAccumulateWithSum()237 public void testGetAndAccumulateWithSum() { 238 AtomicDoubleArray aa = new AtomicDoubleArray(SIZE); 239 for (int i : new int[] {0, SIZE - 1}) { 240 for (double x : VALUES) { 241 for (double y : VALUES) { 242 aa.set(i, x); 243 double z = aa.getAndAccumulate(i, y, Double::sum); 244 assertBitEquals(x, z); 245 assertBitEquals(x + y, aa.get(i)); 246 } 247 } 248 } 249 } 250 251 /** getAndAccumulate with max stores max of given value to current, and returns previous value */ testGetAndAccumulateWithMax()252 public void testGetAndAccumulateWithMax() { 253 AtomicDoubleArray aa = new AtomicDoubleArray(SIZE); 254 for (int i : new int[] {0, SIZE - 1}) { 255 for (double x : VALUES) { 256 for (double y : VALUES) { 257 aa.set(i, x); 258 double z = aa.getAndAccumulate(i, y, Double::max); 259 double expectedMax = max(x, y); 260 assertBitEquals(x, z); 261 assertBitEquals(expectedMax, aa.get(i)); 262 } 263 } 264 } 265 } 266 267 /** accumulateAndGet with sum adds given value to current, and returns current value */ testAccumulateAndGetWithSum()268 public void testAccumulateAndGetWithSum() { 269 AtomicDoubleArray aa = new AtomicDoubleArray(SIZE); 270 for (int i : new int[] {0, SIZE - 1}) { 271 for (double x : VALUES) { 272 for (double y : VALUES) { 273 aa.set(i, x); 274 double z = aa.accumulateAndGet(i, y, Double::sum); 275 assertBitEquals(x + y, z); 276 assertBitEquals(x + y, aa.get(i)); 277 } 278 } 279 } 280 } 281 282 /** accumulateAndGet with max stores max of given value to current, and returns current value */ testAccumulateAndGetWithMax()283 public void testAccumulateAndGetWithMax() { 284 AtomicDoubleArray aa = new AtomicDoubleArray(SIZE); 285 for (int i : new int[] {0, SIZE - 1}) { 286 for (double x : VALUES) { 287 for (double y : VALUES) { 288 aa.set(i, x); 289 double z = aa.accumulateAndGet(i, y, Double::max); 290 double expectedMax = max(x, y); 291 assertBitEquals(expectedMax, z); 292 assertBitEquals(expectedMax, aa.get(i)); 293 } 294 } 295 } 296 } 297 298 /** getAndUpdate adds given value to current, and returns previous value */ testGetAndUpdateWithSum()299 public void testGetAndUpdateWithSum() { 300 AtomicDoubleArray aa = new AtomicDoubleArray(SIZE); 301 for (int i : new int[] {0, SIZE - 1}) { 302 for (double x : VALUES) { 303 for (double y : VALUES) { 304 aa.set(i, x); 305 double z = aa.getAndUpdate(i, value -> value + y); 306 assertBitEquals(x, z); 307 assertBitEquals(x + y, aa.get(i)); 308 } 309 } 310 } 311 } 312 313 /** getAndUpdate subtracts given value to current, and returns previous value */ testGetAndUpdateWithSubtract()314 public void testGetAndUpdateWithSubtract() { 315 AtomicDoubleArray aa = new AtomicDoubleArray(SIZE); 316 for (int i : new int[] {0, SIZE - 1}) { 317 for (double x : VALUES) { 318 for (double y : VALUES) { 319 aa.set(i, x); 320 double z = aa.getAndUpdate(i, value -> value - y); 321 assertBitEquals(x, z); 322 assertBitEquals(x - y, aa.get(i)); 323 } 324 } 325 } 326 } 327 328 /** updateAndGet adds given value to current, and returns current value */ testUpdateAndGetWithSum()329 public void testUpdateAndGetWithSum() { 330 AtomicDoubleArray aa = new AtomicDoubleArray(SIZE); 331 for (int i : new int[] {0, SIZE - 1}) { 332 for (double x : VALUES) { 333 for (double y : VALUES) { 334 aa.set(i, x); 335 double z = aa.updateAndGet(i, value -> value + y); 336 assertBitEquals(x + y, z); 337 assertBitEquals(x + y, aa.get(i)); 338 } 339 } 340 } 341 } 342 343 /** updateAndGet subtracts given value to current, and returns current value */ testUpdateAndGetWithSubtract()344 public void testUpdateAndGetWithSubtract() { 345 AtomicDoubleArray aa = new AtomicDoubleArray(SIZE); 346 for (int i : new int[] {0, SIZE - 1}) { 347 for (double x : VALUES) { 348 for (double y : VALUES) { 349 aa.set(i, x); 350 double z = aa.updateAndGet(i, value -> value - y); 351 assertBitEquals(x - y, z); 352 assertBitEquals(x - y, aa.get(i)); 353 } 354 } 355 } 356 } 357 358 static final long COUNTDOWN = 100000; 359 360 class Counter extends CheckedRunnable { 361 final AtomicDoubleArray aa; 362 volatile long counts; 363 Counter(AtomicDoubleArray a)364 Counter(AtomicDoubleArray a) { 365 aa = a; 366 } 367 368 @Override realRun()369 public void realRun() { 370 for (; ; ) { 371 boolean done = true; 372 for (int i = 0; i < aa.length(); i++) { 373 double v = aa.get(i); 374 assertTrue(v >= 0); 375 if (v != 0) { 376 done = false; 377 if (aa.compareAndSet(i, v, v - 1.0)) { 378 ++counts; 379 } 380 } 381 } 382 if (done) { 383 break; 384 } 385 } 386 } 387 } 388 389 /** 390 * Multiple threads using same array of counters successfully update a number of times equal to 391 * total count 392 */ testCountingInMultipleThreads()393 public void testCountingInMultipleThreads() throws InterruptedException { 394 final AtomicDoubleArray aa = new AtomicDoubleArray(SIZE); 395 for (int i = 0; i < SIZE; i++) { 396 aa.set(i, (double) COUNTDOWN); 397 } 398 Counter c1 = new Counter(aa); 399 Counter c2 = new Counter(aa); 400 Thread t1 = newStartedThread(c1); 401 Thread t2 = newStartedThread(c2); 402 awaitTermination(t1); 403 awaitTermination(t2); 404 assertEquals(SIZE * COUNTDOWN, c1.counts + c2.counts); 405 } 406 407 /** a deserialized serialized array holds same values */ testSerialization()408 public void testSerialization() throws Exception { 409 AtomicDoubleArray x = new AtomicDoubleArray(SIZE); 410 for (int i = 0; i < SIZE; i++) { 411 x.set(i, (double) -i); 412 } 413 AtomicDoubleArray y = serialClone(x); 414 assertTrue(x != y); 415 assertEquals(x.length(), y.length()); 416 for (int i = 0; i < SIZE; i++) { 417 assertBitEquals(x.get(i), y.get(i)); 418 } 419 420 AtomicDoubleArray a = new AtomicDoubleArray(VALUES); 421 AtomicDoubleArray b = serialClone(a); 422 assertFalse(a.equals(b)); 423 assertFalse(b.equals(a)); 424 assertEquals(a.length(), b.length()); 425 for (int i = 0; i < VALUES.length; i++) { 426 assertBitEquals(a.get(i), b.get(i)); 427 } 428 } 429 430 /** toString returns current value */ testToString()431 public void testToString() { 432 AtomicDoubleArray aa = new AtomicDoubleArray(VALUES); 433 assertEquals(Arrays.toString(VALUES), aa.toString()); 434 assertEquals("[]", new AtomicDoubleArray(0).toString()); 435 assertEquals("[]", new AtomicDoubleArray(new double[0]).toString()); 436 } 437 438 /** compareAndSet treats +0.0 and -0.0 as distinct values */ testDistinctZeros()439 public void testDistinctZeros() { 440 AtomicDoubleArray aa = new AtomicDoubleArray(SIZE); 441 for (int i : new int[] {0, SIZE - 1}) { 442 assertFalse(aa.compareAndSet(i, -0.0, 7.0)); 443 assertFalse(aa.weakCompareAndSet(i, -0.0, 7.0)); 444 assertBitEquals(+0.0, aa.get(i)); 445 assertTrue(aa.compareAndSet(i, +0.0, -0.0)); 446 assertBitEquals(-0.0, aa.get(i)); 447 assertFalse(aa.compareAndSet(i, +0.0, 7.0)); 448 assertFalse(aa.weakCompareAndSet(i, +0.0, 7.0)); 449 assertBitEquals(-0.0, aa.get(i)); 450 } 451 } 452 } 453