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