1 /* 2 * Copyright (c) 2019, 2023, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. 8 * 9 * This code is distributed in the hope that it will be useful, but WITHOUT 10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 12 * version 2 for more details (a copy is included in the LICENSE file that 13 * accompanied this code). 14 * 15 * You should have received a copy of the GNU General Public License version 16 * 2 along with this work; if not, write to the Free Software Foundation, 17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 18 * 19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 20 * or visit www.oracle.com if you need additional information or have any 21 * questions. 22 */ 23 24 /* 25 * @test id=default 26 * @bug 8284161 8286788 27 * @summary Test Thread API with virtual threads 28 * @enablePreview 29 * @modules java.base/java.lang:+open 30 * @library /test/lib 31 * @run junit ThreadAPI 32 */ 33 34 /* 35 * @test id=no-vmcontinuations 36 * @requires vm.continuations 37 * @enablePreview 38 * @modules java.base/java.lang:+open 39 * @library /test/lib 40 * @run junit/othervm -XX:+UnlockExperimentalVMOptions -XX:-VMContinuations ThreadAPI 41 */ 42 43 import java.time.Duration; 44 import java.util.Arrays; 45 import java.util.ArrayList; 46 import java.util.List; 47 import java.util.Map; 48 import java.util.Set; 49 import java.util.concurrent.CopyOnWriteArrayList; 50 import java.util.concurrent.CountDownLatch; 51 import java.util.concurrent.ExecutorService; 52 import java.util.concurrent.Executor; 53 import java.util.concurrent.Executors; 54 import java.util.concurrent.ForkJoinPool; 55 import java.util.concurrent.ScheduledExecutorService; 56 import java.util.concurrent.ThreadFactory; 57 import java.util.concurrent.TimeUnit; 58 import java.util.concurrent.atomic.AtomicBoolean; 59 import java.util.concurrent.atomic.AtomicReference; 60 import java.util.concurrent.locks.LockSupport; 61 import java.util.concurrent.locks.ReentrantLock; 62 import java.util.stream.Stream; 63 import java.nio.channels.Selector; 64 65 import jdk.test.lib.thread.VThreadRunner; 66 import org.junit.jupiter.api.Test; 67 import org.junit.jupiter.api.BeforeAll; 68 import org.junit.jupiter.api.AfterAll; 69 import org.junit.jupiter.params.ParameterizedTest; 70 import org.junit.jupiter.params.provider.MethodSource; 71 import static org.junit.jupiter.api.Assertions.*; 72 import static org.junit.jupiter.api.Assumptions.*; 73 74 class ThreadAPI { 75 private static final Object lock = new Object(); 76 77 // used for scheduling thread interrupt 78 private static ScheduledExecutorService scheduler; 79 80 @BeforeAll 81 static void setup() throws Exception { 82 ThreadFactory factory = Executors.defaultThreadFactory(); 83 scheduler = Executors.newSingleThreadScheduledExecutor(factory); 84 } 85 86 @AfterAll 87 static void finish() { 88 scheduler.shutdown(); 89 } 90 91 /** 92 * An operation that does not return a result but may throw an exception. 93 */ 94 @FunctionalInterface 95 interface ThrowingRunnable { 96 void run() throws Exception; 97 } 98 99 /** 100 * Test Thread.currentThread before/after park. 101 */ 102 @Test 103 void testCurrentThread1() throws Exception { 104 var before = new AtomicReference<Thread>(); 105 var after = new AtomicReference<Thread>(); 106 var thread = Thread.ofVirtual().start(() -> { 107 before.set(Thread.currentThread()); 108 LockSupport.park(); 109 after.set(Thread.currentThread()); 110 }); 111 awaitParked(thread); 112 LockSupport.unpark(thread); 113 thread.join(); 114 assertTrue(before.get() == thread); 115 assertTrue(after.get() == thread); 116 } 117 118 /** 119 * Test Thread.currentThread before/after entering synchronized block. 120 */ 121 @Test 122 void testCurrentThread2() throws Exception { 123 var ref1 = new AtomicReference<Thread>(); 124 var ref2 = new AtomicReference<Thread>(); 125 var ref3 = new AtomicReference<Thread>(); 126 var thread = Thread.ofVirtual().unstarted(() -> { 127 ref1.set(Thread.currentThread()); 128 synchronized (lock) { 129 ref2.set(Thread.currentThread()); 130 } 131 ref3.set(Thread.currentThread()); 132 }); 133 synchronized (lock) { 134 thread.start(); 135 awaitBlocked(thread); 136 } 137 thread.join(); 138 assertTrue(ref1.get() == thread); 139 assertTrue(ref2.get() == thread); 140 assertTrue(ref3.get() == thread); 141 } 142 143 /** 144 * Test Thread.currentThread before/after acquiring lock. 145 */ 146 @Test 147 void testCurrentThread3() throws Exception { 148 var ref1 = new AtomicReference<Thread>(); 149 var ref2 = new AtomicReference<Thread>(); 150 var ref3 = new AtomicReference<Thread>(); 151 var lock = new ReentrantLock(); 152 var thread = Thread.ofVirtual().unstarted(() -> { 153 ref1.set(Thread.currentThread()); 154 lock.lock(); 155 try { 156 ref2.set(Thread.currentThread()); 157 } finally { 158 lock.unlock(); 159 } 160 ref3.set(Thread.currentThread()); 161 }); 162 lock.lock(); 163 try { 164 thread.start(); 165 awaitParked(thread); 166 } finally { 167 lock.unlock(); 168 } 169 thread.join(); 170 assertTrue(ref1.get() == thread); 171 assertTrue(ref2.get() == thread); 172 assertTrue(ref3.get() == thread); 173 } 174 175 /** 176 * Test Thread::run. 177 */ 178 @Test 179 void testRun1() throws Exception { 180 var ref = new AtomicBoolean(); 181 var thread = Thread.ofVirtual().unstarted(() -> ref.set(true)); 182 thread.run(); 183 assertFalse(ref.get()); 184 } 185 186 /** 187 * Test Thread::start. 188 */ 189 @Test 190 void testStart1() throws Exception { 191 var ref = new AtomicBoolean(); 192 var thread = Thread.ofVirtual().unstarted(() -> ref.set(true)); 193 assertFalse(ref.get()); 194 thread.start(); 195 thread.join(); 196 assertTrue(ref.get()); 197 } 198 199 /** 200 * Test Thread::start, thread already started. 201 */ 202 @Test 203 void testStart2() throws Exception { 204 var thread = Thread.ofVirtual().start(LockSupport::park); 205 try { 206 assertThrows(IllegalThreadStateException.class, thread::start); 207 } finally { 208 LockSupport.unpark(thread); 209 thread.join(); 210 } 211 } 212 213 /** 214 * Test Thread::start, thread already terminated. 215 */ 216 @Test 217 void testStart3() throws Exception { 218 var thread = Thread.ofVirtual().start(() -> { }); 219 thread.join(); 220 assertThrows(IllegalThreadStateException.class, thread::start); 221 } 222 223 /** 224 * Test Thread.startVirtualThread. 225 */ 226 @Test 227 void testStartVirtualThread() throws Exception { 228 var ref = new AtomicReference<Thread>(); 229 Thread vthread = Thread.startVirtualThread(() -> { 230 ref.set(Thread.currentThread()); 231 LockSupport.park(); 232 }); 233 try { 234 assertTrue(vthread.isVirtual()); 235 236 // Thread.currentThread() returned by the virtual thread 237 Thread current; 238 while ((current = ref.get()) == null) { 239 Thread.sleep(10); 240 } 241 assertTrue(current == vthread); 242 } finally { 243 LockSupport.unpark(vthread); 244 } 245 246 assertThrows(NullPointerException.class, () -> Thread.startVirtualThread(null)); 247 } 248 249 /** 250 * Test Thread::stop from current thread. 251 */ 252 @Test 253 void testStop1() throws Exception { 254 VThreadRunner.run(() -> { 255 Thread t = Thread.currentThread(); 256 assertThrows(UnsupportedOperationException.class, t::stop); 257 }); 258 } 259 260 /** 261 * Test Thread::stop from another thread. 262 */ 263 @Test 264 void testStop2() throws Exception { 265 var thread = Thread.ofVirtual().start(() -> { 266 try { 267 Thread.sleep(20*1000); 268 } catch (InterruptedException e) { } 269 }); 270 try { 271 assertThrows(UnsupportedOperationException.class, thread::stop); 272 } finally { 273 thread.interrupt(); 274 thread.join(); 275 } 276 } 277 278 /** 279 * Test Thread::suspend from current thread. 280 */ 281 @Test 282 void testSuspend1() throws Exception { 283 VThreadRunner.run(() -> { 284 Thread t = Thread.currentThread(); 285 assertThrows(UnsupportedOperationException.class, t::suspend); 286 }); 287 } 288 289 /** 290 * Test Thread::suspend from another thread. 291 */ 292 @Test 293 void testSuspend2() throws Exception { 294 var thread = Thread.ofVirtual().start(() -> { 295 try { 296 Thread.sleep(20*1000); 297 } catch (InterruptedException e) { } 298 }); 299 try { 300 assertThrows(UnsupportedOperationException.class, () -> thread.suspend()); 301 } finally { 302 thread.interrupt(); 303 thread.join(); 304 } 305 } 306 307 /** 308 * Test Thread::resume from current thread. 309 */ 310 @Test 311 void testResume1() throws Exception { 312 VThreadRunner.run(() -> { 313 Thread t = Thread.currentThread(); 314 assertThrows(UnsupportedOperationException.class, t::resume); 315 }); 316 } 317 318 /** 319 * Test Thread::resume from another thread. 320 */ 321 @Test 322 void testResume2() throws Exception { 323 var thread = Thread.ofVirtual().start(() -> { 324 try { 325 Thread.sleep(20*1000); 326 } catch (InterruptedException e) { } 327 }); 328 try { 329 assertThrows(UnsupportedOperationException.class, () -> thread.resume()); 330 } finally { 331 thread.interrupt(); 332 thread.join(); 333 } 334 } 335 336 /** 337 * Test Thread.join before thread starts, platform thread invokes join. 338 */ 339 @Test 340 void testJoin1() throws Exception { 341 var thread = Thread.ofVirtual().unstarted(() -> { }); 342 343 thread.join(); 344 thread.join(0); 345 thread.join(0, 0); 346 thread.join(100); 347 thread.join(100, 0); 348 assertThrows(IllegalThreadStateException.class, 349 () -> thread.join(Duration.ofMillis(-100))); 350 assertThrows(IllegalThreadStateException.class, 351 () -> thread.join(Duration.ofMillis(0))); 352 assertThrows(IllegalThreadStateException.class, 353 () -> thread.join(Duration.ofMillis(100))); 354 } 355 356 /** 357 * Test Thread.join before thread starts, virtual thread invokes join. 358 */ 359 @Test 360 void testJoin2() throws Exception { 361 VThreadRunner.run(this::testJoin1); 362 } 363 364 /** 365 * Test Thread.join where thread does not terminate, platform thread invokes join. 366 */ 367 @Test 368 void testJoin3() throws Exception { 369 var thread = Thread.ofVirtual().start(LockSupport::park); 370 try { 371 thread.join(20); 372 thread.join(20, 0); 373 thread.join(20, 20); 374 thread.join(0, 20); 375 assertFalse(thread.join(Duration.ofMillis(-20))); 376 assertFalse(thread.join(Duration.ofMillis(0))); 377 assertFalse(thread.join(Duration.ofMillis(20))); 378 assertTrue(thread.isAlive()); 379 } finally { 380 LockSupport.unpark(thread); 381 thread.join(); 382 } 383 } 384 385 /** 386 * Test Thread.join where thread does not terminate, virtual thread invokes join. 387 */ 388 @Test 389 void testJoin4() throws Exception { 390 VThreadRunner.run(this::testJoin3); 391 } 392 393 /** 394 * Test Thread.join where thread terminates, platform thread invokes join. 395 */ 396 @Test 397 void testJoin5() throws Exception { 398 var thread = Thread.ofVirtual().start(() -> { 399 try { 400 Thread.sleep(50); 401 } catch (InterruptedException e) { } 402 }); 403 thread.join(); 404 assertFalse(thread.isAlive()); 405 } 406 407 /** 408 * Test Thread.join where thread terminates, virtual thread invokes join. 409 */ 410 @Test 411 void testJoin6() throws Exception { 412 VThreadRunner.run(this::testJoin5); 413 } 414 415 /** 416 * Test Thread.join where thread terminates, platform thread invokes timed-join. 417 */ 418 @Test 419 void testJoin7() throws Exception { 420 var thread = Thread.ofVirtual().start(() -> { 421 try { 422 Thread.sleep(50); 423 } catch (InterruptedException e) { } 424 }); 425 thread.join(10*1000); 426 assertFalse(thread.isAlive()); 427 } 428 429 /** 430 * Test Thread.join where thread terminates, virtual thread invokes timed-join. 431 */ 432 @Test 433 void testJoin8() throws Exception { 434 VThreadRunner.run(this::testJoin7); 435 } 436 437 /** 438 * Test Thread.join where thread terminates, platform thread invokes timed-join. 439 */ 440 @Test 441 void testJoin11() throws Exception { 442 var thread = Thread.ofVirtual().start(() -> { 443 try { 444 Thread.sleep(50); 445 } catch (InterruptedException e) { } 446 }); 447 assertTrue(thread.join(Duration.ofSeconds(10))); 448 assertFalse(thread.isAlive()); 449 } 450 451 /** 452 * Test Thread.join where thread terminates, virtual thread invokes timed-join. 453 */ 454 @Test 455 void testJoin12() throws Exception { 456 VThreadRunner.run(this::testJoin11); 457 } 458 459 /** 460 * Test Thread.join where thread already terminated, platform thread invokes join. 461 */ 462 @Test 463 void testJoin13() throws Exception { 464 var thread = Thread.ofVirtual().start(() -> { }); 465 while (thread.isAlive()) { 466 Thread.sleep(10); 467 } 468 thread.join(); 469 thread.join(0); 470 thread.join(0, 0); 471 thread.join(100); 472 thread.join(100, 0); 473 assertTrue(thread.join(Duration.ofMillis(-100))); 474 assertTrue(thread.join(Duration.ofMillis(0))); 475 assertTrue(thread.join(Duration.ofMillis(100))); 476 } 477 478 /** 479 * Test Thread.join where thread already terminated, virtual thread invokes join. 480 */ 481 @Test 482 void testJoin14() throws Exception { 483 VThreadRunner.run(this::testJoin13); 484 } 485 486 /** 487 * Test platform thread invoking Thread.join with interrupt status set. 488 */ 489 @Test 490 void testJoin15() throws Exception { 491 var thread = Thread.ofVirtual().start(LockSupport::park); 492 Thread.currentThread().interrupt(); 493 try { 494 assertThrows(InterruptedException.class, thread::join); 495 } finally { 496 Thread.interrupted(); 497 LockSupport.unpark(thread); 498 thread.join(); 499 } 500 } 501 502 /** 503 * Test virtual thread invoking Thread.join with interrupt status set. 504 */ 505 @Test 506 void testJoin16() throws Exception { 507 VThreadRunner.run(this::testJoin15); 508 } 509 510 /** 511 * Test platform thread invoking timed-Thread.join with interrupt status set. 512 */ 513 @Test 514 void testJoin17() throws Exception { 515 var thread = Thread.ofVirtual().start(LockSupport::park); 516 Thread.currentThread().interrupt(); 517 try { 518 assertThrows(InterruptedException.class, () -> thread.join(100)); 519 } finally { 520 Thread.interrupted(); 521 LockSupport.unpark(thread); 522 thread.join(); 523 } 524 } 525 526 /** 527 * Test virtual thread invoking timed-Thread.join with interrupt status set. 528 */ 529 @Test 530 void testJoin18() throws Exception { 531 VThreadRunner.run(this::testJoin17); 532 } 533 534 /** 535 * Test platform thread invoking timed-Thread.join with interrupt status set. 536 */ 537 @Test 538 void testJoin19() throws Exception { 539 var thread = Thread.ofVirtual().start(LockSupport::park); 540 Thread.currentThread().interrupt(); 541 try { 542 assertThrows(InterruptedException.class, 543 () -> thread.join(Duration.ofMillis(100))); 544 } finally { 545 Thread.interrupted(); 546 LockSupport.unpark(thread); 547 thread.join(); 548 } 549 } 550 551 /** 552 * Test virtual thread invoking timed-Thread.join with interrupt status set. 553 */ 554 @Test 555 void testJoin20() throws Exception { 556 VThreadRunner.run(this::testJoin19); 557 } 558 559 /** 560 * Test interrupt of platform thread blocked in Thread.join. 561 */ 562 @Test 563 void testJoin21() throws Exception { 564 var thread = Thread.ofVirtual().start(LockSupport::park); 565 scheduleInterrupt(Thread.currentThread(), 100); 566 try { 567 assertThrows(InterruptedException.class, thread::join); 568 } finally { 569 Thread.interrupted(); 570 LockSupport.unpark(thread); 571 thread.join(); 572 } 573 } 574 575 /** 576 * Test interrupt of virtual thread blocked in Thread.join. 577 */ 578 @Test 579 void testJoin22() throws Exception { 580 VThreadRunner.run(this::testJoin17); 581 } 582 583 /** 584 * Test interrupt of platform thread blocked in timed-Thread.join. 585 */ 586 @Test 587 void testJoin23() throws Exception { 588 var thread = Thread.ofVirtual().start(LockSupport::park); 589 scheduleInterrupt(Thread.currentThread(), 100); 590 try { 591 assertThrows(InterruptedException.class, () -> thread.join(10*1000)); 592 } finally { 593 Thread.interrupted(); 594 LockSupport.unpark(thread); 595 thread.join(); 596 } 597 } 598 599 /** 600 * Test interrupt of virtual thread blocked in Thread.join. 601 */ 602 @Test 603 void testJoin24() throws Exception { 604 VThreadRunner.run(this::testJoin23); 605 } 606 607 /** 608 * Test interrupt of platform thread blocked in Thread.join. 609 */ 610 @Test 611 void testJoin25() throws Exception { 612 var thread = Thread.ofVirtual().start(LockSupport::park); 613 scheduleInterrupt(Thread.currentThread(), 100); 614 try { 615 assertThrows(InterruptedException.class, 616 () -> thread.join(Duration.ofSeconds(10))); 617 } finally { 618 Thread.interrupted(); 619 LockSupport.unpark(thread); 620 thread.join(); 621 } 622 } 623 624 /** 625 * Test interrupt of virtual thread blocked in Thread.join. 626 */ 627 @Test 628 void testJoin26() throws Exception { 629 VThreadRunner.run(this::testJoin25); 630 } 631 632 /** 633 * Test virtual thread calling Thread.join to wait for platform thread to terminate. 634 */ 635 @Test 636 void testJoin27() throws Exception { 637 AtomicBoolean done = new AtomicBoolean(); 638 VThreadRunner.run(() -> { 639 var thread = new Thread(() -> { 640 while (!done.get()) { 641 LockSupport.park(); 642 } 643 }); 644 thread.start(); 645 try { 646 assertFalse(thread.join(Duration.ofMillis(-100))); 647 assertFalse(thread.join(Duration.ofMillis(0))); 648 assertFalse(thread.join(Duration.ofMillis(100))); 649 } finally { 650 done.set(true); 651 LockSupport.unpark(thread); 652 thread.join(); 653 } 654 }); 655 } 656 657 /** 658 * Test virtual thread calling Thread.join to wait for platform thread to terminate. 659 */ 660 @Test 661 void testJoin28() throws Exception { 662 long nanos = TimeUnit.NANOSECONDS.convert(100, TimeUnit.MILLISECONDS); 663 VThreadRunner.run(() -> { 664 var thread = new Thread(() -> LockSupport.parkNanos(nanos)); 665 thread.start(); 666 try { 667 assertTrue(thread.join(Duration.ofSeconds(Integer.MAX_VALUE))); 668 assertFalse(thread.isAlive()); 669 } finally { 670 LockSupport.unpark(thread); 671 thread.join(); 672 } 673 }); 674 } 675 676 /** 677 * Test virtual thread with interrupt status set calling Thread.join to wait 678 * for platform thread to terminate. 679 */ 680 @Test 681 void testJoin29() throws Exception { 682 VThreadRunner.run(() -> { 683 var thread = new Thread(LockSupport::park); 684 thread.start(); 685 Thread.currentThread().interrupt(); 686 try { 687 thread.join(Duration.ofSeconds(Integer.MAX_VALUE)); 688 fail("join not interrupted"); 689 } catch (InterruptedException expected) { 690 assertFalse(Thread.interrupted()); 691 } finally { 692 LockSupport.unpark(thread); 693 thread.join(); 694 } 695 }); 696 } 697 698 /** 699 * Test interrupting virtual thread that is waiting in Thread.join for 700 * platform thread to terminate. 701 */ 702 @Test 703 void testJoin30() throws Exception { 704 VThreadRunner.run(() -> { 705 AtomicBoolean done = new AtomicBoolean(); 706 var thread = new Thread(() -> { 707 while (!done.get()) { 708 LockSupport.park(); 709 } 710 }); 711 thread.start(); 712 scheduleInterrupt(Thread.currentThread(), 100); 713 try { 714 thread.join(Duration.ofSeconds(Integer.MAX_VALUE)); 715 fail("join not interrupted"); 716 } catch (InterruptedException expected) { 717 assertFalse(Thread.interrupted()); 718 } finally { 719 done.set(true); 720 LockSupport.unpark(thread); 721 thread.join(); 722 } 723 }); 724 } 725 726 /** 727 * Test platform thread invoking Thread.join on a thread that is parking 728 * and unparking. 729 */ 730 @Test 731 void testJoin31() throws Exception { 732 Thread thread = Thread.ofVirtual().start(() -> { 733 synchronized (lock) { 734 for (int i = 0; i < 10; i++) { 735 LockSupport.parkNanos(Duration.ofMillis(20).toNanos()); 736 } 737 } 738 }); 739 thread.join(); 740 assertFalse(thread.isAlive()); 741 } 742 743 /** 744 * Test virtual thread invoking Thread.join on a thread that is parking 745 * and unparking. 746 */ 747 @Test 748 void testJoin32() throws Exception { 749 VThreadRunner.run(this::testJoin31); 750 } 751 752 /** 753 * Test platform thread invoking timed-Thread.join on a thread that is parking 754 * and unparking while pinned. 755 */ 756 @Test 757 void testJoin33() throws Exception { 758 AtomicBoolean done = new AtomicBoolean(); 759 Thread thread = Thread.ofVirtual().start(() -> { 760 synchronized (lock) { 761 while (!done.get()) { 762 LockSupport.parkNanos(Duration.ofMillis(20).toNanos()); 763 } 764 } 765 }); 766 try { 767 assertFalse(thread.join(Duration.ofMillis(100))); 768 } finally { 769 done.set(true); 770 } 771 } 772 773 /** 774 * Test virtual thread invoking timed-Thread.join on a thread that is parking 775 * and unparking while pinned. 776 */ 777 @Test 778 void testJoin34() throws Exception { 779 // need at least two carrier threads due to pinning 780 int previousParallelism = VThreadRunner.ensureParallelism(2); 781 try { 782 VThreadRunner.run(this::testJoin33); 783 } finally { 784 // restore 785 VThreadRunner.setParallelism(previousParallelism); 786 } 787 } 788 789 /** 790 * Test Thread.join(null). 791 */ 792 @Test 793 void testJoin35() throws Exception { 794 var thread = Thread.ofVirtual().unstarted(LockSupport::park); 795 796 // unstarted 797 assertThrows(NullPointerException.class, () -> thread.join(null)); 798 799 // started 800 thread.start(); 801 try { 802 assertThrows(NullPointerException.class, () -> thread.join(null)); 803 } finally { 804 LockSupport.unpark(thread); 805 } 806 thread.join(); 807 808 // terminated 809 assertThrows(NullPointerException.class, () -> thread.join(null)); 810 } 811 812 /** 813 * Test Thread.interrupt on current thread. 814 */ 815 @Test 816 void testInterrupt1() throws Exception { 817 VThreadRunner.run(() -> { 818 Thread me = Thread.currentThread(); 819 assertFalse(me.isInterrupted()); 820 me.interrupt(); 821 assertTrue(me.isInterrupted()); 822 Thread.interrupted(); // clear interrupt status 823 assertFalse(me.isInterrupted()); 824 me.interrupt(); 825 }); 826 } 827 828 /** 829 * Test Thread.interrupt before thread started. 830 */ 831 @Test 832 void testInterrupt2() throws Exception { 833 var thread = Thread.ofVirtual().unstarted(() -> { }); 834 thread.interrupt(); 835 assertTrue(thread.isInterrupted()); 836 } 837 838 /** 839 * Test Thread.interrupt after thread started. 840 */ 841 @Test 842 void testInterrupt3() throws Exception { 843 var thread = Thread.ofVirtual().start(() -> { }); 844 thread.join(); 845 thread.interrupt(); 846 assertTrue(thread.isInterrupted()); 847 } 848 849 /** 850 * Test termination with interrupt status set. 851 */ 852 @Test 853 void testInterrupt4() throws Exception { 854 var thread = Thread.ofVirtual().start(() -> { 855 Thread.currentThread().interrupt(); 856 }); 857 thread.join(); 858 assertTrue(thread.isInterrupted()); 859 } 860 861 /** 862 * Test Thread.interrupt of thread blocked in Selector.select. 863 */ 864 @Test 865 void testInterrupt5() throws Exception { 866 var exception = new AtomicReference<Exception>(); 867 var thread = Thread.ofVirtual().start(() -> { 868 try { 869 try (var sel = Selector.open()) { 870 sel.select(); 871 assertTrue(Thread.currentThread().isInterrupted()); 872 } 873 } catch (Exception e) { 874 exception.set(e); 875 } 876 }); 877 Thread.sleep(100); // give time for thread to block 878 thread.interrupt(); 879 thread.join(); 880 assertNull(exception.get()); 881 } 882 883 /** 884 * Test Thread.interrupt of thread parked in sleep. 885 */ 886 @Test 887 void testInterrupt6() throws Exception { 888 var exception = new AtomicReference<Exception>(); 889 var thread = Thread.ofVirtual().start(() -> { 890 try { 891 try { 892 Thread.sleep(60*1000); 893 fail("sleep not interrupted"); 894 } catch (InterruptedException e) { 895 // interrupt status should be reset 896 assertFalse(Thread.interrupted()); 897 } 898 } catch (Exception e) { 899 exception.set(e); 900 } 901 }); 902 awaitParked(thread); 903 thread.interrupt(); 904 thread.join(); 905 assertNull(exception.get()); 906 } 907 908 /** 909 * Test Thread.interrupt of parked thread. 910 */ 911 @Test 912 void testInterrupt7() throws Exception { 913 var exception = new AtomicReference<Exception>(); 914 var thread = Thread.ofVirtual().start(() -> { 915 try { 916 LockSupport.park(); 917 assertTrue(Thread.currentThread().isInterrupted()); 918 } catch (Exception e) { 919 exception.set(e); 920 } 921 }); 922 awaitParked(thread); 923 thread.interrupt(); 924 thread.join(); 925 assertNull(exception.get()); 926 } 927 928 /** 929 * Test trying to park with interrupt status set. 930 */ 931 @Test 932 void testInterrupt8() throws Exception { 933 VThreadRunner.run(() -> { 934 Thread me = Thread.currentThread(); 935 me.interrupt(); 936 LockSupport.park(); 937 assertTrue(Thread.interrupted()); 938 }); 939 } 940 941 /** 942 * Test trying to wait with interrupt status set. 943 */ 944 @Test 945 void testInterrupt9() throws Exception { 946 VThreadRunner.run(() -> { 947 Thread me = Thread.currentThread(); 948 me.interrupt(); 949 synchronized (lock) { 950 try { 951 lock.wait(); 952 fail("wait not interrupted"); 953 } catch (InterruptedException expected) { 954 assertFalse(Thread.interrupted()); 955 } 956 } 957 }); 958 } 959 960 /** 961 * Test trying to block with interrupt status set. 962 */ 963 @Test 964 void testInterrupt10() throws Exception { 965 VThreadRunner.run(() -> { 966 Thread me = Thread.currentThread(); 967 me.interrupt(); 968 try (Selector sel = Selector.open()) { 969 sel.select(); 970 assertTrue(Thread.interrupted()); 971 } 972 }); 973 } 974 975 /** 976 * Test Thread.getName and setName from current thread, started without name. 977 */ 978 @Test 979 void testSetName1() throws Exception { 980 VThreadRunner.run(() -> { 981 Thread me = Thread.currentThread(); 982 assertTrue(me.getName().isEmpty()); 983 me.setName("fred"); 984 assertEquals("fred", me.getName()); 985 }); 986 } 987 988 /** 989 * Test Thread.getName and setName from current thread, started with name. 990 */ 991 @Test 992 void testSetName2() throws Exception { 993 VThreadRunner.run("fred", () -> { 994 Thread me = Thread.currentThread(); 995 assertEquals("fred", me.getName()); 996 me.setName("joe"); 997 assertEquals("joe", me.getName()); 998 }); 999 } 1000 1001 /** 1002 * Test Thread.getName and setName from another thread. 1003 */ 1004 @Test 1005 void testSetName3() throws Exception { 1006 var thread = Thread.ofVirtual().unstarted(LockSupport::park); 1007 assertTrue(thread.getName().isEmpty()); 1008 1009 // not started 1010 thread.setName("fred1"); 1011 assertEquals("fred1", thread.getName()); 1012 1013 // started 1014 thread.start(); 1015 try { 1016 assertEquals("fred1", thread.getName()); 1017 thread.setName("fred2"); 1018 assertEquals("fred2", thread.getName()); 1019 } finally { 1020 LockSupport.unpark(thread); 1021 thread.join(); 1022 } 1023 1024 // terminated 1025 assertEquals("fred2", thread.getName()); 1026 thread.setName("fred3"); 1027 assertEquals("fred3", thread.getName()); 1028 } 1029 1030 /** 1031 * Test Thread.getPriority and setPriority from current thread. 1032 */ 1033 @Test 1034 void testSetPriority1() throws Exception { 1035 VThreadRunner.run(() -> { 1036 Thread me = Thread.currentThread(); 1037 assertTrue(me.getPriority() == Thread.NORM_PRIORITY); 1038 1039 me.setPriority(Thread.MAX_PRIORITY); 1040 assertTrue(me.getPriority() == Thread.NORM_PRIORITY); 1041 1042 me.setPriority(Thread.NORM_PRIORITY); 1043 assertTrue(me.getPriority() == Thread.NORM_PRIORITY); 1044 1045 me.setPriority(Thread.MIN_PRIORITY); 1046 assertTrue(me.getPriority() == Thread.NORM_PRIORITY); 1047 1048 assertThrows(IllegalArgumentException.class, () -> me.setPriority(-1)); 1049 }); 1050 } 1051 1052 /** 1053 * Test Thread.getPriority and setPriority from another thread. 1054 */ 1055 @Test 1056 void testSetPriority2() throws Exception { 1057 var thread = Thread.ofVirtual().unstarted(LockSupport::park); 1058 1059 // not started 1060 assertTrue(thread.getPriority() == Thread.NORM_PRIORITY); 1061 1062 thread.setPriority(Thread.MAX_PRIORITY); 1063 assertTrue(thread.getPriority() == Thread.NORM_PRIORITY); 1064 1065 thread.setPriority(Thread.NORM_PRIORITY); 1066 assertTrue(thread.getPriority() == Thread.NORM_PRIORITY); 1067 1068 thread.setPriority(Thread.MIN_PRIORITY); 1069 assertTrue(thread.getPriority() == Thread.NORM_PRIORITY); 1070 1071 assertThrows(IllegalArgumentException.class, () -> thread.setPriority(-1)); 1072 1073 // running 1074 thread.start(); 1075 try { 1076 assertTrue(thread.getPriority() == Thread.NORM_PRIORITY); 1077 thread.setPriority(Thread.NORM_PRIORITY); 1078 1079 thread.setPriority(Thread.MAX_PRIORITY); 1080 assertTrue(thread.getPriority() == Thread.NORM_PRIORITY); 1081 1082 thread.setPriority(Thread.NORM_PRIORITY); 1083 assertTrue(thread.getPriority() == Thread.NORM_PRIORITY); 1084 1085 thread.setPriority(Thread.MIN_PRIORITY); 1086 assertTrue(thread.getPriority() == Thread.NORM_PRIORITY); 1087 1088 assertThrows(IllegalArgumentException.class, () -> thread.setPriority(-1)); 1089 1090 } finally { 1091 LockSupport.unpark(thread); 1092 } 1093 thread.join(); 1094 1095 // terminated 1096 assertTrue(thread.getPriority() == Thread.NORM_PRIORITY); 1097 } 1098 1099 /** 1100 * Test Thread.isDaemon and setDaemon from current thread. 1101 */ 1102 @Test 1103 void testSetDaemon1() throws Exception { 1104 VThreadRunner.run(() -> { 1105 Thread me = Thread.currentThread(); 1106 assertTrue(me.isDaemon()); 1107 assertThrows(IllegalThreadStateException.class, () -> me.setDaemon(true)); 1108 assertThrows(IllegalArgumentException.class, () -> me.setDaemon(false)); 1109 }); 1110 } 1111 1112 /** 1113 * Test Thread.isDaemon and setDaemon from another thread. 1114 */ 1115 @Test 1116 void testSetDaemon2() throws Exception { 1117 var thread = Thread.ofVirtual().unstarted(LockSupport::park); 1118 1119 // not started 1120 assertTrue(thread.isDaemon()); 1121 thread.setDaemon(true); 1122 assertThrows(IllegalArgumentException.class, () -> thread.setDaemon(false)); 1123 1124 // running 1125 thread.start(); 1126 try { 1127 assertTrue(thread.isDaemon()); 1128 assertThrows(IllegalThreadStateException.class, () -> thread.setDaemon(true)); 1129 assertThrows(IllegalArgumentException.class, () -> thread.setDaemon(false)); 1130 } finally { 1131 LockSupport.unpark(thread); 1132 } 1133 thread.join(); 1134 1135 // terminated 1136 assertTrue(thread.isDaemon()); 1137 } 1138 1139 /** 1140 * Test Thread.yield releases thread when not pinned. 1141 */ 1142 @Test 1143 void testYield1() throws Exception { 1144 assumeTrue(ThreadBuilders.supportsCustomScheduler(), "No support for custom schedulers"); 1145 var list = new CopyOnWriteArrayList<String>(); 1146 try (ExecutorService scheduler = Executors.newFixedThreadPool(1)) { 1147 Thread.Builder builder = ThreadBuilders.virtualThreadBuilder(scheduler); 1148 ThreadFactory factory = builder.factory(); 1149 var thread = factory.newThread(() -> { 1150 list.add("A"); 1151 var child = factory.newThread(() -> { 1152 list.add("B"); 1153 Thread.yield(); 1154 list.add("B"); 1155 }); 1156 child.start(); 1157 Thread.yield(); 1158 list.add("A"); 1159 try { child.join(); } catch (InterruptedException e) { } 1160 }); 1161 thread.start(); 1162 thread.join(); 1163 } 1164 assertEquals(List.of("A", "B", "A", "B"), list); 1165 } 1166 1167 /** 1168 * Test Thread.yield when thread is pinned. 1169 */ 1170 @Test 1171 void testYield2() throws Exception { 1172 assumeTrue(ThreadBuilders.supportsCustomScheduler(), "No support for custom schedulers"); 1173 var list = new CopyOnWriteArrayList<String>(); 1174 try (ExecutorService scheduler = Executors.newFixedThreadPool(1)) { 1175 Thread.Builder builder = ThreadBuilders.virtualThreadBuilder(scheduler); 1176 ThreadFactory factory = builder.factory(); 1177 var thread = factory.newThread(() -> { 1178 list.add("A"); 1179 var child = factory.newThread(() -> { 1180 list.add("B"); 1181 }); 1182 child.start(); 1183 synchronized (lock) { 1184 Thread.yield(); // pinned so will be a no-op 1185 list.add("A"); 1186 } 1187 try { child.join(); } catch (InterruptedException e) { } 1188 }); 1189 thread.start(); 1190 thread.join(); 1191 } 1192 assertEquals(List.of("A", "A", "B"), list); 1193 } 1194 1195 /** 1196 * Test Thread.onSpinWait. 1197 */ 1198 @Test 1199 void testOnSpinWait() throws Exception { 1200 VThreadRunner.run(() -> { 1201 Thread me = Thread.currentThread(); 1202 Thread.onSpinWait(); 1203 assertTrue(Thread.currentThread() == me); 1204 }); 1205 } 1206 1207 /** 1208 * Test Thread.sleep(-1). 1209 */ 1210 @Test 1211 void testSleep1() throws Exception { 1212 VThreadRunner.run(() -> { 1213 assertThrows(IllegalArgumentException.class, () -> Thread.sleep(-1)); 1214 assertThrows(IllegalArgumentException.class, () -> Thread.sleep(-1, 0)); 1215 assertThrows(IllegalArgumentException.class, () -> Thread.sleep(0, -1)); 1216 assertThrows(IllegalArgumentException.class, () -> Thread.sleep(0, 1_000_000)); 1217 }); 1218 VThreadRunner.run(() -> Thread.sleep(Duration.ofMillis(-1))); 1219 } 1220 1221 /** 1222 * Test Thread.sleep(0). 1223 */ 1224 @Test 1225 void testSleep2() throws Exception { 1226 VThreadRunner.run(() -> Thread.sleep(0)); 1227 VThreadRunner.run(() -> Thread.sleep(0, 0)); 1228 VThreadRunner.run(() -> Thread.sleep(Duration.ofMillis(0))); 1229 } 1230 1231 /** 1232 * Tasks that sleep for 1 second. 1233 */ 1234 static Stream<ThrowingRunnable> oneSecondSleepers() { 1235 return Stream.of( 1236 () -> Thread.sleep(1000), 1237 () -> Thread.sleep(Duration.ofSeconds(1)) 1238 ); 1239 } 1240 1241 /** 1242 * Test Thread.sleep duration. 1243 */ 1244 @ParameterizedTest 1245 @MethodSource("oneSecondSleepers") 1246 void testSleep3(ThrowingRunnable sleeper) throws Exception { 1247 VThreadRunner.run(() -> { 1248 long start = millisTime(); 1249 sleeper.run(); 1250 expectDuration(start, /*min*/900, /*max*/4000); 1251 }); 1252 } 1253 1254 /** 1255 * Tasks that sleep for zero or longer duration. 1256 */ 1257 static Stream<ThrowingRunnable> sleepers() { 1258 return Stream.of( 1259 () -> Thread.sleep(0), 1260 () -> Thread.sleep(0, 0), 1261 () -> Thread.sleep(1000), 1262 () -> Thread.sleep(1000, 0), 1263 () -> Thread.sleep(Duration.ofMillis(0)), 1264 () -> Thread.sleep(Duration.ofMillis(1000)) 1265 ); 1266 } 1267 1268 /** 1269 * Test Thread.sleep with interrupt status set. 1270 */ 1271 @ParameterizedTest 1272 @MethodSource("sleepers") 1273 void testSleep4(ThrowingRunnable sleeper) throws Exception { 1274 VThreadRunner.run(() -> { 1275 Thread me = Thread.currentThread(); 1276 me.interrupt(); 1277 try { 1278 sleeper.run(); 1279 fail("sleep was not interrupted"); 1280 } catch (InterruptedException e) { 1281 // expected 1282 assertFalse(me.isInterrupted()); 1283 } 1284 }); 1285 } 1286 1287 /** 1288 * Test Thread.sleep with interrupt status set and a negative duration. 1289 */ 1290 @Test 1291 void testSleep4() throws Exception { 1292 VThreadRunner.run(() -> { 1293 Thread me = Thread.currentThread(); 1294 me.interrupt(); 1295 Thread.sleep(Duration.ofMillis(-1000)); // does nothing 1296 assertTrue(me.isInterrupted()); 1297 }); 1298 } 1299 1300 /** 1301 * Tasks that sleep for a long time. 1302 */ 1303 static Stream<ThrowingRunnable> longSleepers() { 1304 return Stream.of( 1305 () -> Thread.sleep(20_000), 1306 () -> Thread.sleep(20_000, 0), 1307 () -> Thread.sleep(Duration.ofSeconds(20)) 1308 ); 1309 } 1310 1311 /** 1312 * Test interrupting Thread.sleep. 1313 */ 1314 @ParameterizedTest 1315 @MethodSource("longSleepers") 1316 void testSleep5(ThrowingRunnable sleeper) throws Exception { 1317 VThreadRunner.run(() -> { 1318 Thread t = Thread.currentThread(); 1319 scheduleInterrupt(t, 100); 1320 try { 1321 sleeper.run(); 1322 fail("sleep was not interrupted"); 1323 } catch (InterruptedException e) { 1324 // interrupt status should be cleared 1325 assertFalse(t.isInterrupted()); 1326 } 1327 }); 1328 } 1329 1330 /** 1331 * Test that Thread.sleep does not disrupt parking permit. 1332 */ 1333 @Test 1334 void testSleep6() throws Exception { 1335 VThreadRunner.run(() -> { 1336 LockSupport.unpark(Thread.currentThread()); 1337 1338 long start = millisTime(); 1339 Thread.sleep(1000); 1340 expectDuration(start, /*min*/900, /*max*/4000); 1341 1342 // check that parking permit was not consumed 1343 LockSupport.park(); 1344 }); 1345 } 1346 1347 /** 1348 * Test that Thread.sleep is not disrupted by unparking thread. 1349 */ 1350 @Test 1351 void testSleep7() throws Exception { 1352 AtomicReference<Exception> exc = new AtomicReference<>(); 1353 var thread = Thread.ofVirtual().start(() -> { 1354 try { 1355 long start = millisTime(); 1356 Thread.sleep(1000); 1357 expectDuration(start, /*min*/900, /*max*/4000); 1358 } catch (Exception e) { 1359 exc.set(e); 1360 } 1361 1362 }); 1363 // attempt to disrupt sleep 1364 for (int i = 0; i < 5; i++) { 1365 Thread.sleep(20); 1366 LockSupport.unpark(thread); 1367 } 1368 thread.join(); 1369 Exception e = exc.get(); 1370 if (e != null) { 1371 throw e; 1372 } 1373 } 1374 1375 /** 1376 * Test Thread.sleep when pinned. 1377 */ 1378 @Test 1379 void testSleep8() throws Exception { 1380 VThreadRunner.run(() -> { 1381 long start = millisTime(); 1382 synchronized (lock) { 1383 Thread.sleep(1000); 1384 } 1385 expectDuration(start, /*min*/900, /*max*/4000); 1386 }); 1387 } 1388 1389 /** 1390 * Test Thread.sleep when pinned and with interrupt status set. 1391 */ 1392 @Test 1393 void testSleep9() throws Exception { 1394 VThreadRunner.run(() -> { 1395 Thread me = Thread.currentThread(); 1396 me.interrupt(); 1397 try { 1398 synchronized (lock) { 1399 Thread.sleep(2000); 1400 } 1401 fail("sleep not interrupted"); 1402 } catch (InterruptedException e) { 1403 // expected 1404 assertFalse(me.isInterrupted()); 1405 } 1406 }); 1407 } 1408 1409 /** 1410 * Test interrupting Thread.sleep when pinned. 1411 */ 1412 @Test 1413 void testSleep10() throws Exception { 1414 VThreadRunner.run(() -> { 1415 Thread t = Thread.currentThread(); 1416 scheduleInterrupt(t, 100); 1417 try { 1418 synchronized (lock) { 1419 Thread.sleep(20 * 1000); 1420 } 1421 fail("sleep not interrupted"); 1422 } catch (InterruptedException e) { 1423 // interrupt status should be cleared 1424 assertFalse(t.isInterrupted()); 1425 } 1426 }); 1427 } 1428 1429 /** 1430 * Test Thread.sleep(null). 1431 */ 1432 @Test 1433 void testSleep11() throws Exception { 1434 assertThrows(NullPointerException.class, () -> Thread.sleep(null)); 1435 VThreadRunner.run(() -> { 1436 assertThrows(NullPointerException.class, () -> Thread.sleep(null)); 1437 }); 1438 } 1439 1440 /** 1441 * Returns the current time in milliseconds. 1442 */ 1443 private static long millisTime() { 1444 long now = System.nanoTime(); 1445 return TimeUnit.MILLISECONDS.convert(now, TimeUnit.NANOSECONDS); 1446 } 1447 1448 /** 1449 * Check the duration of a task 1450 * @param start start time, in milliseconds 1451 * @param min minimum expected duration, in milliseconds 1452 * @param max maximum expected duration, in milliseconds 1453 * @return the duration (now - start), in milliseconds 1454 */ 1455 private static void expectDuration(long start, long min, long max) { 1456 long duration = millisTime() - start; 1457 assertTrue(duration >= min, 1458 "Duration " + duration + "ms, expected >= " + min + "ms"); 1459 assertTrue(duration <= max, 1460 "Duration " + duration + "ms, expected <= " + max + "ms"); 1461 } 1462 1463 /** 1464 * Test Thread.xxxContextClassLoader from the current thread. 1465 */ 1466 @Test 1467 void testContextClassLoader1() throws Exception { 1468 ClassLoader loader = new ClassLoader() { }; 1469 VThreadRunner.run(() -> { 1470 Thread t = Thread.currentThread(); 1471 t.setContextClassLoader(loader); 1472 assertTrue(t.getContextClassLoader() == loader); 1473 }); 1474 } 1475 1476 /** 1477 * Test inheriting initial value of TCCL from platform thread. 1478 */ 1479 @Test 1480 void testContextClassLoader2() throws Exception { 1481 ClassLoader loader = new ClassLoader() { }; 1482 Thread t = Thread.currentThread(); 1483 ClassLoader savedLoader = t.getContextClassLoader(); 1484 t.setContextClassLoader(loader); 1485 try { 1486 VThreadRunner.run(() -> { 1487 assertTrue(Thread.currentThread().getContextClassLoader() == loader); 1488 }); 1489 } finally { 1490 t.setContextClassLoader(savedLoader); 1491 } 1492 } 1493 1494 /** 1495 * Test inheriting initial value of TCCL from virtual thread. 1496 */ 1497 @Test 1498 void testContextClassLoader3() throws Exception { 1499 VThreadRunner.run(() -> { 1500 ClassLoader loader = new ClassLoader() { }; 1501 Thread.currentThread().setContextClassLoader(loader); 1502 VThreadRunner.run(() -> { 1503 assertTrue(Thread.currentThread().getContextClassLoader() == loader); 1504 }); 1505 }); 1506 } 1507 1508 /** 1509 * Test inheriting initial value of TCCL through an intermediate virtual thread. 1510 */ 1511 @Test 1512 void testContextClassLoader4() throws Exception { 1513 ClassLoader loader = new ClassLoader() { }; 1514 Thread t = Thread.currentThread(); 1515 ClassLoader savedLoader = t.getContextClassLoader(); 1516 t.setContextClassLoader(loader); 1517 try { 1518 VThreadRunner.run(() -> { 1519 VThreadRunner.run(() -> { 1520 assertTrue(Thread.currentThread().getContextClassLoader() == loader); 1521 }); 1522 }); 1523 } finally { 1524 t.setContextClassLoader(savedLoader); 1525 } 1526 } 1527 1528 /** 1529 * Test Thread.xxxContextClassLoader when thread locals not supported. 1530 */ 1531 @Test 1532 void testContextClassLoader5() throws Exception { 1533 ClassLoader scl = ClassLoader.getSystemClassLoader(); 1534 ClassLoader loader = new ClassLoader() { }; 1535 VThreadRunner.run(VThreadRunner.NO_THREAD_LOCALS, () -> { 1536 Thread t = Thread.currentThread(); 1537 assertTrue(t.getContextClassLoader() == scl); 1538 assertThrows(UnsupportedOperationException.class, 1539 () -> t.setContextClassLoader(loader)); 1540 assertTrue(t.getContextClassLoader() == scl); 1541 }); 1542 } 1543 1544 /** 1545 * Test Thread.xxxContextClassLoader when thread does not inherit the 1546 * initial value of inheritable thread locals. 1547 */ 1548 @Test 1549 void testContextClassLoader6() throws Exception { 1550 VThreadRunner.run(() -> { 1551 ClassLoader loader = new ClassLoader() { }; 1552 Thread.currentThread().setContextClassLoader(loader); 1553 int characteristics = VThreadRunner.NO_INHERIT_THREAD_LOCALS; 1554 VThreadRunner.run(characteristics, () -> { 1555 Thread t = Thread.currentThread(); 1556 assertTrue(t.getContextClassLoader() == ClassLoader.getSystemClassLoader()); 1557 t.setContextClassLoader(loader); 1558 assertTrue(t.getContextClassLoader() == loader); 1559 }); 1560 }); 1561 } 1562 1563 /** 1564 * Test Thread.setUncaughtExceptionHandler. 1565 */ 1566 @Test 1567 void testUncaughtExceptionHandler1() throws Exception { 1568 class FooException extends RuntimeException { } 1569 var exception = new AtomicReference<Throwable>(); 1570 Thread.UncaughtExceptionHandler handler = (thread, exc) -> exception.set(exc); 1571 Thread thread = Thread.ofVirtual().start(() -> { 1572 Thread me = Thread.currentThread(); 1573 assertTrue(me.getUncaughtExceptionHandler() == me.getThreadGroup()); 1574 me.setUncaughtExceptionHandler(handler); 1575 assertTrue(me.getUncaughtExceptionHandler() == handler); 1576 throw new FooException(); 1577 }); 1578 thread.join(); 1579 assertTrue(exception.get() instanceof FooException); 1580 assertNull(thread.getUncaughtExceptionHandler()); 1581 } 1582 1583 /** 1584 * Test default UncaughtExceptionHandler. 1585 */ 1586 @Test 1587 void testUncaughtExceptionHandler2() throws Exception { 1588 class FooException extends RuntimeException { } 1589 var exception = new AtomicReference<Throwable>(); 1590 Thread.UncaughtExceptionHandler handler = (thread, exc) -> exception.set(exc); 1591 Thread.UncaughtExceptionHandler savedHandler = Thread.getDefaultUncaughtExceptionHandler(); 1592 Thread.setDefaultUncaughtExceptionHandler(handler); 1593 Thread thread; 1594 try { 1595 thread = Thread.ofVirtual().start(() -> { 1596 Thread me = Thread.currentThread(); 1597 throw new FooException(); 1598 }); 1599 thread.join(); 1600 } finally { 1601 Thread.setDefaultUncaughtExceptionHandler(savedHandler); 1602 } 1603 assertTrue(exception.get() instanceof FooException); 1604 assertNull(thread.getUncaughtExceptionHandler()); 1605 } 1606 1607 /** 1608 * Test no UncaughtExceptionHandler set. 1609 */ 1610 @Test 1611 void testUncaughtExceptionHandler3() throws Exception { 1612 class FooException extends RuntimeException { } 1613 Thread thread = Thread.ofVirtual().start(() -> { 1614 throw new FooException(); 1615 }); 1616 thread.join(); 1617 assertNull(thread.getUncaughtExceptionHandler()); 1618 } 1619 1620 /** 1621 * Test Thread::threadId and getId. 1622 */ 1623 @Test 1624 void testThreadId1() throws Exception { 1625 record ThreadIds(long threadId, long id) { } 1626 var ref = new AtomicReference<ThreadIds>(); 1627 1628 Thread vthread = Thread.ofVirtual().unstarted(() -> { 1629 Thread thread = Thread.currentThread(); 1630 ref.set(new ThreadIds(thread.threadId(), thread.getId())); 1631 LockSupport.park(); 1632 }); 1633 1634 // unstarted 1635 long tid = vthread.threadId(); 1636 1637 // running 1638 ThreadIds tids; 1639 vthread.start(); 1640 try { 1641 while ((tids = ref.get()) == null) { 1642 Thread.sleep(10); 1643 } 1644 assertTrue(tids.threadId() == tid); 1645 assertTrue(tids.id() == tid); 1646 } finally { 1647 LockSupport.unpark(vthread); 1648 vthread.join(); 1649 } 1650 1651 // terminated 1652 assertTrue(vthread.threadId() == tid); 1653 assertTrue(vthread.getId() == tid); 1654 } 1655 1656 /** 1657 * Test that each Thread has a unique ID 1658 */ 1659 @Test 1660 void testThreadId2() throws Exception { 1661 // thread ID should be unique 1662 long tid1 = Thread.ofVirtual().unstarted(() -> { }).threadId(); 1663 long tid2 = Thread.ofVirtual().unstarted(() -> { }).threadId(); 1664 long tid3 = Thread.currentThread().threadId(); 1665 assertFalse(tid1 == tid2); 1666 assertFalse(tid1 == tid3); 1667 assertFalse(tid2 == tid3); 1668 } 1669 1670 /** 1671 * Test Thread::getState when thread is not started. 1672 */ 1673 @Test 1674 void testGetState1() { 1675 var thread = Thread.ofVirtual().unstarted(() -> { }); 1676 assertTrue(thread.getState() == Thread.State.NEW); 1677 } 1678 1679 /** 1680 * Test Thread::getState when thread is runnable (mounted). 1681 */ 1682 @Test 1683 void testGetState2() throws Exception { 1684 VThreadRunner.run(() -> { 1685 Thread.State state = Thread.currentThread().getState(); 1686 assertTrue(state == Thread.State.RUNNABLE); 1687 }); 1688 } 1689 1690 /** 1691 * Test Thread::getState when thread is runnable (not mounted). 1692 */ 1693 @Test 1694 void testGetState3() throws Exception { 1695 assumeTrue(ThreadBuilders.supportsCustomScheduler(), "No support for custom schedulers"); 1696 AtomicBoolean completed = new AtomicBoolean(); 1697 try (ExecutorService scheduler = Executors.newFixedThreadPool(1)) { 1698 Thread.Builder builder = ThreadBuilders.virtualThreadBuilder(scheduler); 1699 Thread t1 = builder.start(() -> { 1700 Thread t2 = builder.unstarted(LockSupport::park); 1701 assertTrue(t2.getState() == Thread.State.NEW); 1702 1703 // start t2 to make it runnable 1704 t2.start(); 1705 try { 1706 assertTrue(t2.getState() == Thread.State.RUNNABLE); 1707 1708 // yield to allow t2 to run and park 1709 Thread.yield(); 1710 assertTrue(t2.getState() == Thread.State.WAITING); 1711 } finally { 1712 // unpark t2 to make it runnable again 1713 LockSupport.unpark(t2); 1714 } 1715 1716 // t2 should be runnable (not mounted) 1717 assertTrue(t2.getState() == Thread.State.RUNNABLE); 1718 1719 completed.set(true); 1720 }); 1721 t1.join(); 1722 } 1723 assertTrue(completed.get() == true); 1724 } 1725 1726 /** 1727 * Test Thread::getState when thread is parked. 1728 */ 1729 @Test 1730 void testGetState4() throws Exception { 1731 var thread = Thread.ofVirtual().start(LockSupport::park); 1732 while (thread.getState() != Thread.State.WAITING) { 1733 Thread.sleep(20); 1734 } 1735 LockSupport.unpark(thread); 1736 thread.join(); 1737 } 1738 1739 /** 1740 * Test Thread::getState when thread is parked while holding a monitor. 1741 */ 1742 @Test 1743 void testGetState5() throws Exception { 1744 var thread = Thread.ofVirtual().start(() -> { 1745 synchronized (lock) { 1746 LockSupport.park(); 1747 } 1748 }); 1749 while (thread.getState() != Thread.State.WAITING) { 1750 Thread.sleep(20); 1751 } 1752 LockSupport.unpark(thread); 1753 thread.join(); 1754 } 1755 1756 /** 1757 * Test Thread::getState when thread is waiting for a monitor. 1758 */ 1759 @Test 1760 void testGetState6() throws Exception { 1761 var thread = Thread.ofVirtual().unstarted(() -> { 1762 synchronized (lock) { } 1763 }); 1764 synchronized (lock) { 1765 thread.start(); 1766 while (thread.getState() != Thread.State.BLOCKED) { 1767 Thread.sleep(20); 1768 } 1769 } 1770 thread.join(); 1771 } 1772 1773 /** 1774 * Test Thread::getState when thread is waiting in Object.wait. 1775 */ 1776 @Test 1777 void testGetState7() throws Exception { 1778 var thread = Thread.ofVirtual().start(() -> { 1779 synchronized (lock) { 1780 try { lock.wait(); } catch (InterruptedException e) { } 1781 } 1782 }); 1783 while (thread.getState() != Thread.State.WAITING) { 1784 Thread.sleep(20); 1785 } 1786 thread.interrupt(); 1787 thread.join(); 1788 } 1789 1790 /** 1791 * Test Thread::getState when thread is terminated. 1792 */ 1793 @Test 1794 void testGetState8() throws Exception { 1795 var thread = Thread.ofVirtual().start(() -> { }); 1796 thread.join(); 1797 assertTrue(thread.getState() == Thread.State.TERMINATED); 1798 } 1799 1800 /** 1801 * Test Thread::isAlive. 1802 */ 1803 @Test 1804 void testIsAlive1() throws Exception { 1805 // unstarted 1806 var thread = Thread.ofVirtual().unstarted(LockSupport::park); 1807 assertFalse(thread.isAlive()); 1808 1809 // started 1810 thread.start(); 1811 try { 1812 assertTrue(thread.isAlive()); 1813 } finally { 1814 LockSupport.unpark(thread); 1815 thread.join(); 1816 } 1817 1818 // terminated 1819 assertFalse(thread.isAlive()); 1820 } 1821 1822 /** 1823 * Test Thread.holdLock when lock not held. 1824 */ 1825 @Test 1826 void testHoldsLock1() throws Exception { 1827 VThreadRunner.run(() -> { 1828 var lock = new Object(); 1829 assertFalse(Thread.holdsLock(lock)); 1830 }); 1831 } 1832 1833 /** 1834 * Test Thread.holdLock when lock held. 1835 */ 1836 @Test 1837 void testHoldsLock2() throws Exception { 1838 VThreadRunner.run(() -> { 1839 var lock = new Object(); 1840 synchronized (lock) { 1841 assertTrue(Thread.holdsLock(lock)); 1842 } 1843 }); 1844 } 1845 1846 /** 1847 * Test Thread::getStackTrace on unstarted thread. 1848 */ 1849 @Test 1850 void testGetStackTrace1() { 1851 var thread = Thread.ofVirtual().unstarted(() -> { }); 1852 StackTraceElement[] stack = thread.getStackTrace(); 1853 assertTrue(stack.length == 0); 1854 } 1855 1856 /** 1857 * Test Thread::getStackTrace on thread that has been started but has not run. 1858 */ 1859 @Test 1860 void testGetStackTrace2() throws Exception { 1861 assumeTrue(ThreadBuilders.supportsCustomScheduler(), "No support for custom schedulers"); 1862 Executor scheduler = task -> { }; 1863 Thread.Builder builder = ThreadBuilders.virtualThreadBuilder(scheduler); 1864 Thread thread = builder.start(() -> { }); 1865 StackTraceElement[] stack = thread.getStackTrace(); 1866 assertTrue(stack.length == 0); 1867 } 1868 1869 /** 1870 * Test Thread::getStackTrace on running thread. 1871 */ 1872 @Test 1873 void testGetStackTrace3() throws Exception { 1874 var sel = Selector.open(); 1875 var thread = Thread.ofVirtual().start(() -> { 1876 try { sel.select(); } catch (Exception e) { } 1877 }); 1878 try { 1879 while (!contains(thread.getStackTrace(), "select")) { 1880 assertTrue(thread.isAlive()); 1881 Thread.sleep(20); 1882 } 1883 } finally { 1884 sel.close(); 1885 thread.join(); 1886 } 1887 } 1888 1889 /** 1890 * Test Thread::getStackTrace on thread waiting in Object.wait. 1891 */ 1892 @Test 1893 void testGetStackTrace4() throws Exception { 1894 assumeTrue(ThreadBuilders.supportsCustomScheduler(), "No support for custom schedulers"); 1895 try (ForkJoinPool pool = new ForkJoinPool(1)) { 1896 AtomicReference<Thread> ref = new AtomicReference<>(); 1897 Executor scheduler = task -> { 1898 pool.submit(() -> { 1899 ref.set(Thread.currentThread()); 1900 task.run(); 1901 }); 1902 }; 1903 1904 Thread.Builder builder = ThreadBuilders.virtualThreadBuilder(scheduler); 1905 Thread vthread = builder.start(() -> { 1906 synchronized (lock) { 1907 try { 1908 lock.wait(); 1909 } catch (Exception e) { } 1910 } 1911 }); 1912 1913 // get carrier Thread 1914 Thread carrier; 1915 while ((carrier = ref.get()) == null) { 1916 Thread.sleep(20); 1917 } 1918 1919 // wait for virtual thread to block in wait 1920 while (vthread.getState() != Thread.State.WAITING) { 1921 Thread.sleep(20); 1922 } 1923 1924 // get stack trace of both carrier and virtual thread 1925 StackTraceElement[] carrierStackTrace = carrier.getStackTrace(); 1926 StackTraceElement[] vthreadStackTrace = vthread.getStackTrace(); 1927 1928 // allow virtual thread to terminate 1929 synchronized (lock) { 1930 lock.notifyAll(); 1931 } 1932 1933 // check carrier thread's stack trace 1934 assertTrue(contains(carrierStackTrace, "java.util.concurrent.ForkJoinPool.runWorker")); 1935 assertFalse(contains(carrierStackTrace, "java.lang.Object.wait")); 1936 1937 // check virtual thread's stack trace 1938 assertFalse(contains(vthreadStackTrace, "java.util.concurrent.ForkJoinPool.runWorker")); 1939 assertTrue(contains(vthreadStackTrace, "java.lang.Object.wait")); 1940 } 1941 } 1942 1943 /** 1944 * Test Thread::getStackTrace on parked thread. 1945 */ 1946 @Test 1947 void testGetStackTrace5() throws Exception { 1948 var thread = Thread.ofVirtual().start(LockSupport::park); 1949 1950 // wait for thread to park 1951 while (thread.getState() != Thread.State.WAITING) { 1952 Thread.sleep(20); 1953 } 1954 1955 try { 1956 StackTraceElement[] stack = thread.getStackTrace(); 1957 assertTrue(contains(stack, "LockSupport.park")); 1958 } finally { 1959 LockSupport.unpark(thread); 1960 thread.join(); 1961 } 1962 } 1963 1964 /** 1965 * Test Thread::getStackTrace on terminated thread. 1966 */ 1967 @Test 1968 void testGetStackTrace6() throws Exception { 1969 var thread = Thread.ofVirtual().start(() -> { }); 1970 thread.join(); 1971 StackTraceElement[] stack = thread.getStackTrace(); 1972 assertTrue(stack.length == 0); 1973 } 1974 1975 /** 1976 * Test that Thread.getAllStackTraces does not include virtual threads. 1977 */ 1978 @Test 1979 void testGetAllStackTraces1() throws Exception { 1980 VThreadRunner.run(() -> { 1981 Set<Thread> threads = Thread.getAllStackTraces().keySet(); 1982 assertFalse(threads.stream().anyMatch(Thread::isVirtual)); 1983 }); 1984 } 1985 1986 /** 1987 * Test that Thread.getAllStackTraces includes carrier threads. 1988 */ 1989 @Test 1990 void testGetAllStackTraces2() throws Exception { 1991 assumeTrue(ThreadBuilders.supportsCustomScheduler(), "No support for custom schedulers"); 1992 try (ForkJoinPool pool = new ForkJoinPool(1)) { 1993 AtomicReference<Thread> ref = new AtomicReference<>(); 1994 Executor scheduler = task -> { 1995 pool.submit(() -> { 1996 ref.set(Thread.currentThread()); 1997 task.run(); 1998 }); 1999 }; 2000 2001 Thread.Builder builder = ThreadBuilders.virtualThreadBuilder(scheduler); 2002 Thread vthread = builder.start(() -> { 2003 synchronized (lock) { 2004 try { 2005 lock.wait(); 2006 } catch (Exception e) { } 2007 } 2008 }); 2009 2010 // get carrier Thread 2011 Thread carrier; 2012 while ((carrier = ref.get()) == null) { 2013 Thread.sleep(20); 2014 } 2015 2016 // wait for virtual thread to block in wait 2017 while (vthread.getState() != Thread.State.WAITING) { 2018 Thread.sleep(20); 2019 } 2020 2021 // get all stack traces 2022 Map<Thread, StackTraceElement[]> map = Thread.getAllStackTraces(); 2023 2024 // allow virtual thread to terminate 2025 synchronized (lock) { 2026 lock.notifyAll(); 2027 } 2028 2029 // get stack trace for the carrier thread 2030 StackTraceElement[] stackTrace = map.get(carrier); 2031 assertNotNull(stackTrace); 2032 assertTrue(contains(stackTrace, "java.util.concurrent.ForkJoinPool")); 2033 assertFalse(contains(stackTrace, "java.lang.Object.wait")); 2034 2035 // there should be no stack trace for the virtual thread 2036 assertNull(map.get(vthread)); 2037 } 2038 } 2039 2040 private boolean contains(StackTraceElement[] stack, String expected) { 2041 return Stream.of(stack) 2042 .map(Object::toString) 2043 .anyMatch(s -> s.contains(expected)); 2044 } 2045 2046 /** 2047 * Test Thread::getThreadGroup on virtual thread created by platform thread. 2048 */ 2049 @Test 2050 void testThreadGroup1() throws Exception { 2051 var thread = Thread.ofVirtual().unstarted(LockSupport::park); 2052 var vgroup = thread.getThreadGroup(); 2053 thread.start(); 2054 try { 2055 assertTrue(thread.getThreadGroup() == vgroup); 2056 } finally { 2057 LockSupport.unpark(thread); 2058 thread.join(); 2059 } 2060 assertNull(thread.getThreadGroup()); 2061 } 2062 2063 /** 2064 * Test Thread::getThreadGroup on platform thread created by virtual thread. 2065 */ 2066 @Test 2067 void testThreadGroup2() throws Exception { 2068 VThreadRunner.run(() -> { 2069 ThreadGroup vgroup = Thread.currentThread().getThreadGroup(); 2070 Thread child = new Thread(() -> { }); 2071 ThreadGroup group = child.getThreadGroup(); 2072 assertTrue(group == vgroup); 2073 }); 2074 } 2075 2076 /** 2077 * Test ThreadGroup returned by Thread::getThreadGroup and subgroup 2078 * created with 2-arg ThreadGroup constructor. 2079 */ 2080 @Test 2081 void testThreadGroup3() throws Exception { 2082 var ref = new AtomicReference<ThreadGroup>(); 2083 var thread = Thread.startVirtualThread(() -> { 2084 ref.set(Thread.currentThread().getThreadGroup()); 2085 }); 2086 thread.join(); 2087 2088 ThreadGroup vgroup = ref.get(); 2089 assertTrue(vgroup.getMaxPriority() == Thread.MAX_PRIORITY); 2090 2091 ThreadGroup group = new ThreadGroup(vgroup, "group"); 2092 assertTrue(group.getParent() == vgroup); 2093 assertTrue(group.getMaxPriority() == Thread.MAX_PRIORITY); 2094 2095 vgroup.setMaxPriority(Thread.MAX_PRIORITY - 1); 2096 assertTrue(vgroup.getMaxPriority() == Thread.MAX_PRIORITY); 2097 assertTrue(group.getMaxPriority() == Thread.MAX_PRIORITY - 1); 2098 2099 vgroup.setMaxPriority(Thread.MIN_PRIORITY); 2100 assertTrue(vgroup.getMaxPriority() == Thread.MAX_PRIORITY); 2101 assertTrue(group.getMaxPriority() == Thread.MIN_PRIORITY); 2102 } 2103 2104 /** 2105 * Test ThreadGroup returned by Thread::getThreadGroup and subgroup 2106 * created with 1-arg ThreadGroup constructor. 2107 */ 2108 @Test 2109 void testThreadGroup4() throws Exception { 2110 VThreadRunner.run(() -> { 2111 ThreadGroup vgroup = Thread.currentThread().getThreadGroup(); 2112 2113 assertTrue(vgroup.getMaxPriority() == Thread.MAX_PRIORITY); 2114 2115 ThreadGroup group = new ThreadGroup("group"); 2116 assertTrue(group.getParent() == vgroup); 2117 assertTrue(group.getMaxPriority() == Thread.MAX_PRIORITY); 2118 2119 vgroup.setMaxPriority(Thread.MAX_PRIORITY - 1); 2120 assertTrue(vgroup.getMaxPriority() == Thread.MAX_PRIORITY); 2121 assertTrue(group.getMaxPriority() == Thread.MAX_PRIORITY - 1); 2122 2123 vgroup.setMaxPriority(Thread.MIN_PRIORITY); 2124 assertTrue(vgroup.getMaxPriority() == Thread.MAX_PRIORITY); 2125 assertTrue(group.getMaxPriority() == Thread.MIN_PRIORITY); 2126 }); 2127 } 2128 2129 /** 2130 * Test Thread.enumerate(false). 2131 */ 2132 @Test 2133 void testEnumerate1() throws Exception { 2134 VThreadRunner.run(() -> { 2135 ThreadGroup vgroup = Thread.currentThread().getThreadGroup(); 2136 Thread[] threads = new Thread[100]; 2137 int n = vgroup.enumerate(threads, /*recurse*/false); 2138 assertTrue(n == 0); 2139 }); 2140 } 2141 2142 /** 2143 * Test Thread.enumerate(true). 2144 */ 2145 @Test 2146 void testEnumerate2() throws Exception { 2147 VThreadRunner.run(() -> { 2148 ThreadGroup vgroup = Thread.currentThread().getThreadGroup(); 2149 Thread[] threads = new Thread[100]; 2150 int n = vgroup.enumerate(threads, /*recurse*/true); 2151 assertFalse(Arrays.stream(threads, 0, n).anyMatch(Thread::isVirtual)); 2152 }); 2153 } 2154 2155 /** 2156 * Test equals and hashCode. 2157 */ 2158 @Test 2159 void testEqualsAndHashCode() throws Exception { 2160 Thread vthread1 = Thread.ofVirtual().unstarted(LockSupport::park); 2161 Thread vthread2 = Thread.ofVirtual().unstarted(LockSupport::park); 2162 2163 // unstarted 2164 assertTrue(vthread1.equals(vthread1)); 2165 assertTrue(vthread2.equals(vthread2)); 2166 assertFalse(vthread1.equals(vthread2)); 2167 assertFalse(vthread2.equals(vthread1)); 2168 int hc1 = vthread1.hashCode(); 2169 int hc2 = vthread2.hashCode(); 2170 2171 vthread1.start(); 2172 vthread2.start(); 2173 try { 2174 // started, maybe running or parked 2175 assertTrue(vthread1.equals(vthread1)); 2176 assertTrue(vthread2.equals(vthread2)); 2177 assertFalse(vthread1.equals(vthread2)); 2178 assertFalse(vthread2.equals(vthread1)); 2179 assertTrue(vthread1.hashCode() == hc1); 2180 assertTrue(vthread2.hashCode() == hc2); 2181 } finally { 2182 LockSupport.unpark(vthread1); 2183 LockSupport.unpark(vthread2); 2184 } 2185 vthread1.join(); 2186 vthread2.join(); 2187 2188 // terminated 2189 assertTrue(vthread1.equals(vthread1)); 2190 assertTrue(vthread2.equals(vthread2)); 2191 assertFalse(vthread1.equals(vthread2)); 2192 assertFalse(vthread2.equals(vthread1)); 2193 assertTrue(vthread1.hashCode() == hc1); 2194 assertTrue(vthread2.hashCode() == hc2); 2195 } 2196 2197 /** 2198 * Test toString on unstarted thread. 2199 */ 2200 @Test 2201 void testToString1() { 2202 Thread thread = Thread.ofVirtual().unstarted(() -> { }); 2203 thread.setName("fred"); 2204 assertTrue(thread.toString().contains("fred")); 2205 } 2206 2207 /** 2208 * Test toString on running thread. 2209 */ 2210 @Test 2211 void testToString2() throws Exception { 2212 VThreadRunner.run(() -> { 2213 Thread me = Thread.currentThread(); 2214 me.setName("fred"); 2215 assertTrue(me.toString().contains("fred")); 2216 }); 2217 } 2218 2219 /** 2220 * Test toString on parked thread. 2221 */ 2222 @Test 2223 void testToString3() throws Exception { 2224 Thread thread = Thread.ofVirtual().start(() -> { 2225 Thread me = Thread.currentThread(); 2226 me.setName("fred"); 2227 LockSupport.park(); 2228 }); 2229 while (thread.getState() != Thread.State.WAITING) { 2230 Thread.sleep(10); 2231 } 2232 try { 2233 assertTrue(thread.toString().contains("fred")); 2234 } finally { 2235 LockSupport.unpark(thread); 2236 thread.join(); 2237 } 2238 } 2239 2240 /** 2241 * Test toString on terminated thread. 2242 */ 2243 @Test 2244 void testToString4() throws Exception { 2245 Thread thread = Thread.ofVirtual().start(() -> { 2246 Thread me = Thread.currentThread(); 2247 me.setName("fred"); 2248 }); 2249 thread.join(); 2250 assertTrue(thread.toString().contains("fred")); 2251 } 2252 2253 /** 2254 * Waits for the given thread to park. 2255 */ 2256 static void awaitParked(Thread thread) throws InterruptedException { 2257 Thread.State state = thread.getState(); 2258 while (state != Thread.State.WAITING && state != Thread.State.TIMED_WAITING) { 2259 assertTrue(state != Thread.State.TERMINATED, "Thread has terminated"); 2260 Thread.sleep(10); 2261 state = thread.getState(); 2262 } 2263 } 2264 2265 /** 2266 * Waits for the given thread to block waiting on a monitor. 2267 */ 2268 static void awaitBlocked(Thread thread) throws InterruptedException { 2269 Thread.State state = thread.getState(); 2270 while (state != Thread.State.BLOCKED) { 2271 assertTrue(state != Thread.State.TERMINATED, "Thread has terminated"); 2272 Thread.sleep(10); 2273 state = thread.getState(); 2274 } 2275 } 2276 2277 /** 2278 * Schedule a thread to be interrupted after a delay. 2279 */ 2280 private void scheduleInterrupt(Thread thread, long delayInMillis) { 2281 scheduler.schedule(thread::interrupt, delayInMillis, TimeUnit.MILLISECONDS); 2282 } 2283 }