1/* 2 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 3 * 4 * This code is free software; you can redistribute it and/or modify it 5 * under the terms of the GNU General Public License version 2 only, as 6 * published by the Free Software Foundation. 7 * 8 * This code is distributed in the hope that it will be useful, but WITHOUT 9 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 10 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 11 * version 2 for more details (a copy is included in the LICENSE file that 12 * accompanied this code). 13 * 14 * You should have received a copy of the GNU General Public License version 15 * 2 along with this work; if not, write to the Free Software Foundation, 16 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 17 * 18 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 19 * or visit www.oracle.com if you need additional information or have any 20 * questions. 21 */ 22 23/* 24 * This file is available under and governed by the GNU General Public 25 * License version 2 only, as published by the Free Software Foundation. 26 * However, the following notice accompanied the original version of this 27 * file: 28 * 29 * Written by Martin Buchholz with assistance from members of JCP 30 * JSR-166 Expert Group and released to the public domain, as 31 * explained at http://creativecommons.org/publicdomain/zero/1.0/ 32 */ 33 34/* 35 * @test 36 * @modules java.base/java.util.concurrent:open 37 * @run testng WhiteBox 38 * @summary White box tests of implementation details 39 */ 40 41import static org.testng.Assert.*; 42import org.testng.annotations.DataProvider; 43import org.testng.annotations.Test; 44 45import java.lang.ref.WeakReference; 46import java.lang.invoke.MethodHandles; 47import java.lang.invoke.VarHandle; 48import java.util.ArrayDeque; 49import java.util.ArrayList; 50import java.util.Arrays; 51import java.util.Collection; 52import java.util.Collections; 53import java.util.Iterator; 54import java.util.List; 55import java.util.NoSuchElementException; 56import java.util.Queue; 57import java.util.concurrent.ArrayBlockingQueue; 58import java.util.concurrent.CountDownLatch; 59import java.util.concurrent.ThreadLocalRandom; 60import java.util.concurrent.TimeUnit; 61import java.util.function.BooleanSupplier; 62 63@Test 64public class WhiteBox { 65 final ThreadLocalRandom rnd = ThreadLocalRandom.current(); 66 final MethodHandles.Lookup lookup = MethodHandles.lookup(); 67 final VarHandle ITRS, ITEMS, TAKEINDEX, PUTINDEX, COUNT, HEAD, NEXT, PREVTAKEINDEX; 68 69 WhiteBox() throws ReflectiveOperationException { 70 Class<?> qClass = ArrayBlockingQueue.class; 71 Class<?> itrClass = Class.forName(qClass.getName() + "$Itr"); 72 Class<?> itrsClass = Class.forName(qClass.getName() + "$Itrs"); 73 Class<?> nodeClass = Class.forName(itrsClass.getName() + "$Node"); 74 ITRS = findVarHandle(qClass, "itrs", itrsClass); 75 ITEMS = findVarHandle(qClass, "items", Object[].class); 76 TAKEINDEX = findVarHandle(qClass, "takeIndex", int.class); 77 PUTINDEX = findVarHandle(qClass, "putIndex", int.class); 78 COUNT = findVarHandle(qClass, "count", int.class); 79 HEAD = findVarHandle(itrsClass, "head", nodeClass); 80 NEXT = findVarHandle(nodeClass, "next", nodeClass); 81 PREVTAKEINDEX = findVarHandle(itrClass, "prevTakeIndex", int.class); 82 } 83 84 VarHandle findVarHandle(Class<?> recv, String name, Class<?> type) 85 throws ReflectiveOperationException { 86 return MethodHandles.privateLookupIn(recv, lookup) 87 .findVarHandle(recv, name, type); 88 } 89 90 Object itrs(ArrayBlockingQueue q) { return ITRS.get(q); } 91 Object[] items(ArrayBlockingQueue q) { return (Object[]) ITEMS.get(q); } 92 int takeIndex(ArrayBlockingQueue q) { return (int) TAKEINDEX.get(q); } 93 int putIndex(ArrayBlockingQueue q) { return (int) PUTINDEX.get(q); } 94 int count(ArrayBlockingQueue q) { return (int) COUNT.get(q); } 95 Object head(Object itrs) { return HEAD.get(itrs); } 96 Object next(Object node) { return NEXT.get(node); } 97 int prevTakeIndex(Iterator itr) { return (int) PREVTAKEINDEX.get(itr); } 98 99 boolean isDetached(Iterator it) { 100 return prevTakeIndex(it) < 0; 101 } 102 103 void assertIteratorExhausted(Iterator it) { 104 if (rnd.nextBoolean()) { 105 assertTrue(!it.hasNext()); 106 assertTrue(isDetached(it)); 107 } 108 if (rnd.nextBoolean()) { 109 it.forEachRemaining(e -> { throw new AssertionError(); }); 110 assertTrue(isDetached(it)); 111 } 112 if (rnd.nextBoolean()) 113 try { it.next(); fail("should throw"); } 114 catch (NoSuchElementException success) {} 115 } 116 117 List<Iterator> trackedIterators(ArrayBlockingQueue q) { 118 List<Iterator> its = new ArrayList<>(); 119 Object itrs = itrs(q); 120 if (itrs != null) { 121 for (Object p = head(itrs); p != null; p = next(p)) 122 its.add(((WeakReference<Iterator>)(p)).get()); 123 Collections.reverse(its); 124 } 125 return its; 126 } 127 128 List<Iterator> attachedIterators(ArrayBlockingQueue q) { 129 List<Iterator> its = new ArrayList<>(); 130 Object itrs = itrs(q); 131 if (itrs != null) { 132 for (Object p = head(itrs); p != null; p = next(p)) { 133 Iterator it = ((WeakReference<Iterator>)(p)).get(); 134 if (it != null && !isDetached(it)) 135 its.add(it); 136 } 137 Collections.reverse(its); 138 } 139 return its; 140 } 141 142 void assertRemoveThrowsISE(Iterator it) { 143 if (rnd.nextBoolean()) 144 try { it.remove(); fail("should throw"); } 145 catch (IllegalStateException success) {} 146 } 147 148 void assertRemoveHasNoEffect(Iterator it, Collection c) { 149 if (rnd.nextBoolean()) { 150 int size = c.size(); 151 it.remove(); // no effect 152 assertEquals(c.size(), size); 153 assertRemoveThrowsISE(it); 154 } 155 } 156 157 void checkIterationSanity(Queue q) { 158 if (rnd.nextBoolean()) 159 return; 160 int size = q.size(); 161 Object[] a = q.toArray(); 162 Object[] b = new Object[size+2]; 163 Arrays.fill(b, Boolean.TRUE); 164 Object[] c = q.toArray(b); 165 assertEquals(a.length, size); 166 assertSame(b, c); 167 assertNull(b[size]); 168 assertSame(b[size+1], Boolean.TRUE); 169 assertEquals(q.toString(), Arrays.toString(a)); 170 Integer[] xx = null, yy = null; 171 if (size > 0) { 172 xx = new Integer[size - 1]; 173 Arrays.fill(xx, 42); 174 yy = ((Queue<Integer>)q).toArray(xx); 175 for (Integer zz : xx) 176 assertEquals(42, (int) zz); 177 } 178 Iterator it = q.iterator(); 179 for (int i = 0; i < size; i++) { 180 if (rnd.nextBoolean()) assertTrue(it.hasNext()); 181 Object x = it.next(); 182 assertSame(x, a[i]); 183 assertSame(x, b[i]); 184 if (xx != null) assertSame(x, yy[i]); 185 } 186 if (rnd.nextBoolean()) assertTrue(!it.hasNext()); 187 } 188 189 /** 190 * Instead of having putIndex (and takeIndex) at the initial 191 * default of 0, move them to a random location. 192 */ 193 void randomizePutIndex(ArrayBlockingQueue q) { 194 assertTrue(q.isEmpty()); 195 int capacity = q.remainingCapacity(); 196 int n = rnd.nextInt(capacity + 1); 197 int putIndex = putIndex(q); 198 for (int i = n; i-->0; ) q.add(Boolean.TRUE); 199 for (int i = n; i-->0; ) q.remove(); 200 assertEquals(putIndex(q), (putIndex + n) % items(q).length); 201 } 202 203 /** No guarantees, but effective in practice. */ 204 static void forceFullGc() { 205 CountDownLatch finalizeDone = new CountDownLatch(1); 206 WeakReference<?> ref = new WeakReference<Object>(new Object() { 207 protected void finalize() { finalizeDone.countDown(); }}); 208 try { 209 for (int i = 0; i < 10; i++) { 210 System.gc(); 211 if (finalizeDone.await(1L, TimeUnit.SECONDS) && ref.get() == null) { 212 System.runFinalization(); // try to pick up stragglers 213 return; 214 } 215 } 216 } catch (InterruptedException unexpected) { 217 throw new AssertionError("unexpected InterruptedException"); 218 } 219 throw new AssertionError("failed to do a \"full\" gc"); 220 } 221 222 static void gcAwait(BooleanSupplier s) { 223 for (int i = 0; i < 10; i++) { 224 if (s.getAsBoolean()) 225 return; 226 forceFullGc(); 227 } 228 throw new AssertionError("failed to satisfy condition"); 229 } 230 231 public void clear_willClearItrs() { 232 boolean fair = rnd.nextBoolean(); 233 int capacity = rnd.nextInt(2, 10); 234 ArrayBlockingQueue q = new ArrayBlockingQueue(capacity, fair); 235 randomizePutIndex(q); 236 List<Iterator> its = new ArrayList<>(); 237 for (int i = 0; i < capacity; i++) 238 assertTrue(q.add(i)); 239 assertNull(itrs(q)); 240 for (int i = 0; i < capacity; i++) { 241 its.add(q.iterator()); 242 assertEquals(trackedIterators(q), its); 243 q.poll(); 244 q.add(capacity + i); 245 } 246 q.clear(); 247 assertNull(itrs(q)); 248 int j = 0; 249 for (Iterator it : its) { 250 assertTrue(isDetached(it)); 251 if (rnd.nextBoolean()) assertTrue(it.hasNext()); 252 if (rnd.nextBoolean()) { 253 assertEquals(it.next(), j); 254 assertIteratorExhausted(it); 255 } 256 j++; 257 } 258 } 259 260 public void queueEmptyingWillClearItrs() { 261 boolean fair = rnd.nextBoolean(); 262 int capacity = rnd.nextInt(2, 10); 263 ArrayBlockingQueue q = new ArrayBlockingQueue(capacity, fair); 264 randomizePutIndex(q); 265 List<Iterator> its = new ArrayList<>(); 266 for (int i = 0; i < capacity; i++) 267 q.add(i); 268 assertNull(itrs(q)); 269 for (int i = 0; i < capacity; i++) { 270 its.add(q.iterator()); 271 assertEquals(trackedIterators(q), its); 272 q.poll(); 273 q.add(capacity+i); 274 } 275 for (int i = 0; i < capacity; i++) 276 q.poll(); 277 assertNull(itrs(q)); 278 int j = 0; 279 for (Iterator it : its) { 280 assertTrue(isDetached(it)); 281 if (rnd.nextBoolean()) assertTrue(it.hasNext()); 282 if (rnd.nextBoolean()) { 283 assertEquals(it.next(), j); 284 assertIteratorExhausted(it); 285 } 286 j++; 287 } 288 } 289 290 public void advancing2CyclesWillRemoveIterators() { 291 boolean fair = rnd.nextBoolean(); 292 int capacity = rnd.nextInt(2, 10); 293 ArrayBlockingQueue q = new ArrayBlockingQueue(capacity, fair); 294 List<Iterator> its = new ArrayList<>(); 295 for (int i = 0; i < capacity; i++) 296 q.add(i); 297 assertNull(itrs(q)); 298 for (int i = capacity; i < 3 * capacity; i++) { 299 its.add(q.iterator()); 300 assertEquals(trackedIterators(q), its); 301 q.poll(); 302 q.add(i); 303 } 304 for (int i = 3 * capacity; i < 4 * capacity; i++) { 305 assertEquals(trackedIterators(q), its.subList(capacity,2*capacity)); 306 q.poll(); 307 q.add(i); 308 } 309 assertNull(itrs(q)); 310 int j = 0; 311 for (Iterator it : its) { 312 assertTrue(isDetached(it)); 313 if (rnd.nextBoolean()) assertTrue(it.hasNext()); 314 if (rnd.nextBoolean()) { 315 assertEquals(it.next(), j); 316 assertIteratorExhausted(it); 317 } 318 j++; 319 } 320 } 321 322 /** 323 * Interior removal of elements used by an iterator will cause it 324 * to be untracked. 325 */ 326 public void interiorRemovalOfElementsUsedByIterator() { 327 boolean fair = rnd.nextBoolean(); 328 int capacity = rnd.nextInt(10, 20); 329 ArrayBlockingQueue q = new ArrayBlockingQueue(capacity, fair); 330 randomizePutIndex(q); 331 q.add(0); 332 for (int i = 1; i < 2 * capacity; i++) { 333 q.add(i); 334 Integer[] elts = { -1, -2, -3 }; 335 for (Integer elt : elts) q.add(elt); 336 assertEquals(q.remove(), i - 1); 337 Iterator it = q.iterator(); 338 assertEquals(it.next(), i); 339 assertEquals(it.next(), elts[0]); 340 Collections.shuffle(Arrays.asList(elts)); 341 assertTrue(q.remove(elts[0])); 342 assertTrue(q.remove(elts[1])); 343 assertEquals(trackedIterators(q), Collections.singletonList(it)); 344 assertTrue(q.remove(elts[2])); 345 assertNull(itrs(q)); 346 assertEquals(it.next(), -2); 347 assertIteratorExhausted(it); 348 assertTrue(isDetached(it)); 349 } 350 } 351 352 public void iteratorsOnEmptyQueue() { 353 boolean fair = rnd.nextBoolean(); 354 int capacity = rnd.nextInt(1, 10); 355 ArrayBlockingQueue q = new ArrayBlockingQueue(capacity, fair); 356 randomizePutIndex(q); 357 for (int i = 0; i < 4; i++) { 358 Iterator it = q.iterator(); 359 assertNull(itrs(q)); 360 assertIteratorExhausted(it); 361 assertTrue(isDetached(it)); 362 assertRemoveThrowsISE(it); 363 } 364 } 365 366 public void interiorRemovalOfIteratorsLastElement() { 367 boolean fair = rnd.nextBoolean(); 368 int capacity = rnd.nextInt(3, 10); 369 ArrayBlockingQueue q = new ArrayBlockingQueue(capacity, fair); 370 randomizePutIndex(q); 371 List<Iterator> its = new ArrayList<>(); 372 for (int i = 0; i < capacity; i++) 373 q.add(i); 374 for (int i = 0; i < capacity; i++) { 375 Iterator it = q.iterator(); 376 its.add(it); 377 for (int j = 0; j < i; j++) 378 assertEquals(j, it.next()); 379 assertEquals(attachedIterators(q), its); 380 } 381 q.remove(capacity - 1); 382 assertEquals(attachedIterators(q), its); 383 for (int i = 1; i < capacity - 1; i++) { 384 q.remove(capacity - i - 1); 385 Iterator it = its.get(capacity - i); 386 assertTrue(isDetached(it)); 387 assertEquals(attachedIterators(q), its.subList(0, capacity - i)); 388 if (rnd.nextBoolean()) assertTrue(it.hasNext()); 389 assertEquals(it.next(), capacity - i); 390 assertIteratorExhausted(it); 391 } 392 assertEquals(attachedIterators(q), its.subList(0, 2)); 393 q.remove(0); 394 assertTrue(q.isEmpty()); 395 assertNull(itrs(q)); 396 Iterator it = its.get(0); 397 assertEquals(it.next(), 0); 398 assertRemoveHasNoEffect(it, q); 399 assertIteratorExhausted(it); 400 assertTrue(isDetached(it)); 401 assertRemoveHasNoEffect(its.get(1), q); 402 } 403 404 /** 405 * Checks "interior" removal of alternating elements, straddling 2 cycles 406 */ 407 public void interiorRemovalOfAlternatingElements() { 408 boolean fair = rnd.nextBoolean(); 409 int capacity = 2 * rnd.nextInt(2, 10); 410 ArrayBlockingQueue q = new ArrayBlockingQueue(capacity, fair); 411 List<Iterator> its = new ArrayList<>(); 412 // Move takeIndex to middle 413 for (int i = 0; i < capacity/2; i++) { 414 assertTrue(q.add(i)); 415 assertEquals(q.poll(), i); 416 } 417 assertEquals(takeIndex(q), capacity/2); 418 for (int i = 0; i < capacity; i++) 419 q.add(i); 420 for (int i = 0; i < capacity; i++) { 421 Iterator it = q.iterator(); 422 its.add(it); 423 for (int j = 0; j < i; j++) 424 assertEquals(j, it.next()); 425 assertEquals(attachedIterators(q), its); 426 } 427 428 // Remove all even elements, in either direction, using 429 // q.remove(), or iterator.remove() 430 switch (rnd.nextInt(3)) { 431 case 0: 432 for (int i = 0; i < capacity; i+=2) assertTrue(q.remove(i)); 433 break; 434 case 1: 435 for (int i = capacity - 2; i >= 0; i-=2) assertTrue(q.remove(i)); 436 break; 437 case 2: 438 Iterator it = q.iterator(); 439 while (it.hasNext()) { 440 int i = (Integer) it.next(); 441 if ((i & 1) == 0) 442 it.remove(); 443 } 444 break; 445 default: throw new AssertionError(); 446 } 447 assertEquals(attachedIterators(q), its); 448 449 for (int i = 0; i < capacity; i++) { 450 Iterator it = its.get(i); 451 boolean even = ((i & 1) == 0); 452 if (even) { 453 if (rnd.nextBoolean()) assertTrue(it.hasNext()); 454 assertEquals(i, it.next()); 455 for (int j = i+1; j < capacity; j += 2) 456 assertEquals(j, it.next()); 457 assertTrue(!isDetached(it)); 458 assertTrue(!it.hasNext()); 459 assertTrue(isDetached(it)); 460 } else { /* odd */ 461 if (rnd.nextBoolean()) assertTrue(it.hasNext()); 462 assertRemoveHasNoEffect(it, q); 463 assertEquals(i, it.next()); 464 for (int j = i+2; j < capacity; j += 2) 465 assertEquals(j, it.next()); 466 assertTrue(!isDetached(it)); 467 assertTrue(!it.hasNext()); 468 assertTrue(isDetached(it)); 469 } 470 } 471 assertEquals(trackedIterators(q), Collections.emptyList()); 472 assertNull(itrs(q)); 473 } 474 475 public void garbageCollectionOfUnreachableIterators() { 476 boolean fair = rnd.nextBoolean(); 477 int capacity = rnd.nextInt(1, 10); 478 ArrayBlockingQueue q = new ArrayBlockingQueue(capacity, fair); 479 randomizePutIndex(q); 480 List<Iterator> its = new ArrayList<>(); 481 for (int i = 0; i < capacity; i++) q.add(i); 482 for (int i = 0; i < capacity; i++) its.add(q.iterator()); 483 assertEquals(attachedIterators(q), its); 484 its = null; 485 gcAwait(() -> { 486 List<Iterator> trackedIterators = trackedIterators(q); 487 assertEquals(trackedIterators.size(), capacity); 488 for (Iterator x : trackedIterators) 489 if (x != null) return false; 490 return true; 491 }); 492 Iterator it = q.iterator(); // 493 assertEquals(trackedIterators(q), Collections.singletonList(it)); 494 } 495 496 public void garbageCollectionOfUnreachableIteratorsWithRandomlyRetainedSubset() { 497 boolean fair = rnd.nextBoolean(); 498 int capacity = rnd.nextInt(10, 20); 499 ArrayBlockingQueue q = new ArrayBlockingQueue(capacity, fair); 500 randomizePutIndex(q); 501 List<Iterator> its = new ArrayList<>(); 502 List<Iterator> retained = new ArrayList<>(); 503 final int size = 1 + rnd.nextInt(capacity); 504 for (int i = 0; i < size; i++) q.add(i); 505 for (int i = 0; i < size; i++) its.add(q.iterator()); 506 assertEquals(attachedIterators(q), its); 507 // Leave sufficient gaps in retained 508 for (int i = 0; i < size; i+= 2+rnd.nextInt(3)) 509 retained.add(its.get(i)); 510 its = null; 511 gcAwait(() -> { 512 List<Iterator> trackedIterators = trackedIterators(q); 513 assertEquals(trackedIterators.size(), size); 514 for (Iterator it : trackedIterators) 515 if ((it != null) ^ retained.contains(it)) return false; 516 return true; 517 }); 518 Iterator it = q.iterator(); // trigger another sweep 519 retained.add(it); 520 assertEquals(trackedIterators(q), retained); 521 } 522 523 /** 524 * Checks incremental sweeping of unreachable iterators. 525 * Excessively white box?! 526 */ 527 public void incrementalSweepingOfUnreachableIterators() { 528 boolean fair = rnd.nextBoolean(); 529 int capacity = rnd.nextInt(10, 20); 530 ArrayBlockingQueue q = new ArrayBlockingQueue(capacity, fair); 531 randomizePutIndex(q); 532 final int SHORT_SWEEP_PROBES = 4; 533 final int LONG_SWEEP_PROBES = 16; 534 final int PROBE_HOP = LONG_SWEEP_PROBES + 6 * SHORT_SWEEP_PROBES; 535 final int PROBE_HOP_COUNT = 10; 536 // Expect around 8 sweeps per PROBE_HOP 537 final int SWEEPS_PER_PROBE_HOP = 8; 538 List<Iterator> its = new ArrayList<>(); 539 for (int i = 0; i < capacity; i++) 540 q.add(i); 541 for (int i = 0; i < PROBE_HOP_COUNT * PROBE_HOP; i++) 542 its.add(q.iterator()); 543 assertEquals(attachedIterators(q), its); 544 // make some garbage, separated by PROBE_HOP 545 for (int i = 0; i < its.size(); i += PROBE_HOP) 546 its.set(i, null); 547 its.removeIf(it -> it == null); 548 forceFullGc(); 549 int retries; 550 for (retries = 0; 551 trackedIterators(q).contains(null) && retries < 1000; 552 retries++) 553 // one round of sweeping 554 its.add(q.iterator()); 555 assertTrue(retries >= PROBE_HOP_COUNT * (SWEEPS_PER_PROBE_HOP - 2)); 556 assertTrue(retries <= PROBE_HOP_COUNT * (SWEEPS_PER_PROBE_HOP + 2)); 557 assertEquals(trackedIterators(q), its); 558 } 559 560 public void Iterator_remove_safetyWhileInDetachedMode() { 561 boolean fair = rnd.nextBoolean(); 562 int capacity = rnd.nextInt(10, 20); 563 ArrayBlockingQueue q = new ArrayBlockingQueue(capacity, fair); 564 List<Iterator> its = new ArrayList<>(); 565 for (int i = 0; i < capacity/2; i++) { 566 q.add(i); 567 q.remove(); 568 } 569 assertEquals(takeIndex(q), capacity/2); 570 for (int i = 0; i < capacity; i++) 571 q.add(i); 572 for (int i = 0; i < capacity; i++) { 573 Iterator it = q.iterator(); 574 its.add(it); 575 for (int j = 0; j < i; j++) 576 assertEquals(j, it.next()); 577 } 578 assertEquals(attachedIterators(q), its); 579 for (int i = capacity - 1; i >= 0; i--) { 580 Iterator it = its.get(i); 581 assertEquals(i, it.next()); // last element 582 assertTrue(!isDetached(it)); 583 assertTrue(!it.hasNext()); // first hasNext failure 584 assertTrue(isDetached(it)); 585 int size = q.size(); 586 assertTrue(q.contains(i)); 587 switch (rnd.nextInt(3)) { 588 case 0: 589 it.remove(); 590 assertTrue(!q.contains(i)); 591 assertEquals(q.size(), size - 1); 592 break; 593 case 1: 594 // replace i with impostor 595 if (q.remainingCapacity() == 0) { 596 assertTrue(q.remove(i)); 597 assertTrue(q.add(-1)); 598 } else { 599 assertTrue(q.add(-1)); 600 assertTrue(q.remove(i)); 601 } 602 it.remove(); // should have no effect 603 assertEquals(size, q.size()); 604 assertTrue(q.contains(-1)); 605 assertTrue(q.remove(-1)); 606 break; 607 case 2: 608 // replace i with true impostor 609 if (i != 0) { 610 assertTrue(q.remove(i)); 611 assertTrue(q.add(i)); 612 } 613 it.remove(); 614 assertTrue(!q.contains(i)); 615 assertEquals(q.size(), size - 1); 616 break; 617 default: throw new AssertionError(); 618 } 619 assertRemoveThrowsISE(it); 620 assertTrue(isDetached(it)); 621 assertTrue(!trackedIterators(q).contains(it)); 622 } 623 assertTrue(q.isEmpty()); 624 assertNull(itrs(q)); 625 for (Iterator it : its) 626 assertIteratorExhausted(it); 627 } 628 629 /** 630 * Checks dequeues bypassing iterators' current positions. 631 */ 632 public void dequeuesBypassingIteratorCurrentPositions() { 633 boolean fair = rnd.nextBoolean(); 634 int capacity = rnd.nextInt(10, 20); 635 ArrayBlockingQueue q = new ArrayBlockingQueue(capacity, fair); 636 Queue<Iterator> its0 = new ArrayDeque<>(); 637 Queue<Iterator> itsMid = new ArrayDeque<>(); 638 List<Iterator> its = new ArrayList<>(); 639 for (int i = 0; i < capacity; i++) 640 q.add(i); 641 for (int i = 0; i < 2 * capacity + 1; i++) { 642 Iterator it = q.iterator(); 643 its.add(it); 644 its0.add(it); 645 } 646 for (int i = 0; i < 2 * capacity + 1; i++) { 647 Iterator it = q.iterator(); 648 for (int j = 0; j < capacity/2; j++) 649 assertEquals(j, it.next()); 650 its.add(it); 651 itsMid.add(it); 652 } 653 for (int i = capacity; i < 3 * capacity; i++) { 654 Iterator it; 655 656 it = its0.remove(); 657 assertRemoveThrowsISE(it); 658 if (rnd.nextBoolean()) assertTrue(it.hasNext()); 659 assertEquals(0, it.next()); 660 int victim = i - capacity; 661 for (int j = victim + (victim == 0 ? 1 : 0); j < i; j++) { 662 if (rnd.nextBoolean()) assertTrue(it.hasNext()); 663 assertEquals(j, it.next()); 664 } 665 assertIteratorExhausted(it); 666 667 it = itsMid.remove(); 668 if (victim >= capacity/2) 669 assertRemoveHasNoEffect(it, q); 670 assertEquals(capacity/2, it.next()); 671 if (victim > capacity/2) 672 assertRemoveHasNoEffect(it, q); 673 for (int j = Math.max(victim, capacity/2 + 1); j < i; j++) { 674 if (rnd.nextBoolean()) assertTrue(it.hasNext()); 675 assertEquals(j, it.next()); 676 } 677 assertIteratorExhausted(it); 678 679 if (rnd.nextBoolean()) { 680 assertEquals(victim, q.remove()); 681 } else { 682 ArrayList list = new ArrayList(1); 683 q.drainTo(list, 1); 684 assertEquals(list.size(), 1); 685 assertEquals(victim, list.get(0)); 686 } 687 assertTrue(q.add(i)); 688 } 689 // takeIndex has wrapped twice. 690 Iterator it0 = its0.remove(); 691 Iterator itMid = itsMid.remove(); 692 assertTrue(isDetached(it0)); 693 assertTrue(isDetached(itMid)); 694 if (rnd.nextBoolean()) assertTrue(it0.hasNext()); 695 if (rnd.nextBoolean()) assertTrue(itMid.hasNext()); 696 assertRemoveThrowsISE(it0); 697 assertRemoveHasNoEffect(itMid, q); 698 if (rnd.nextBoolean()) assertEquals(0, it0.next()); 699 if (rnd.nextBoolean()) assertEquals(capacity/2, itMid.next()); 700 assertTrue(isDetached(it0)); 701 assertTrue(isDetached(itMid)); 702 assertEquals(capacity, q.size()); 703 assertEquals(0, q.remainingCapacity()); 704 } 705 706 /** 707 * Checks collective sanity of iteration, toArray() and toString(). 708 */ 709 public void collectiveSanity() { 710 boolean fair = rnd.nextBoolean(); 711 int capacity = rnd.nextInt(10, 20); 712 ArrayBlockingQueue q = new ArrayBlockingQueue(capacity, fair); 713 randomizePutIndex(q); 714 for (int i = 0; i < capacity; i++) { 715 checkIterationSanity(q); 716 assertEquals(capacity, q.size() + q.remainingCapacity()); 717 q.add(i); 718 } 719 for (int i = 0; i < (capacity + (capacity >> 1)); i++) { 720 checkIterationSanity(q); 721 assertEquals(capacity, q.size() + q.remainingCapacity()); 722 assertEquals(i, q.peek()); 723 assertEquals(i, q.poll()); 724 checkIterationSanity(q); 725 assertEquals(capacity, q.size() + q.remainingCapacity()); 726 q.add(capacity + i); 727 } 728 for (int i = 0; i < capacity; i++) { 729 checkIterationSanity(q); 730 assertEquals(capacity, q.size() + q.remainingCapacity()); 731 int expected = i + capacity + (capacity >> 1); 732 assertEquals(expected, q.peek()); 733 assertEquals(expected, q.poll()); 734 } 735 checkIterationSanity(q); 736 } 737 738 public void iteratorsDetachedWhenExhaustedAndLastRetRemoved() { 739 boolean fair = rnd.nextBoolean(); 740 int capacity = rnd.nextInt(2, 10); 741 ArrayBlockingQueue q = new ArrayBlockingQueue(capacity, fair); 742 randomizePutIndex(q); 743 int size = rnd.nextInt(1, capacity + 1); 744 for (int i = 0; i < size; i++) q.add(i); 745 Iterator it = q.iterator(); 746 for (int i = 0; i < size - 1; i++) assertEquals(i, it.next()); 747 assertEquals(trackedIterators(q), Collections.singletonList(it)); 748 assertFalse(isDetached(it)); 749 switch (rnd.nextInt(2)) { 750 case 0: assertTrue(q.remove(size - 1)); break; 751 case 1: assertTrue(q.removeIf(e -> e.equals(size - 1))); break; 752 default: throw new AssertionError(); 753 } 754 assertEquals(size - 1, it.next()); // should trigger detach 755 assertNull(itrs(q)); 756 assertTrue(isDetached(it)); 757 assertRemoveHasNoEffect(it, q); 758 } 759} 760