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 26 * @summary Unit test for Thread.Builder 27 * @enablePreview 28 * @run junit BuilderTest 29 */ 30 31 import java.util.concurrent.*; 32 import java.util.concurrent.atomic.AtomicBoolean; 33 import java.util.concurrent.atomic.AtomicReference; 34 import java.util.concurrent.locks.LockSupport; 35 36 import org.junit.jupiter.api.Test; 37 import static org.junit.jupiter.api.Assertions.*; 38 import static org.junit.jupiter.api.Assumptions.*; 39 40 class BuilderTest { 41 42 /** 43 * Test Thread.ofPlatform to create platform threads. 44 */ 45 @Test 46 void testPlatformThread() throws Exception { 47 Thread parent = Thread.currentThread(); 48 Thread.Builder.OfPlatform builder = Thread.ofPlatform(); 49 50 // unstarted 51 AtomicBoolean done1 = new AtomicBoolean(); 52 Thread thread1 = builder.unstarted(() -> done1.set(true)); 53 assertFalse(thread1.isVirtual()); 54 assertTrue(thread1.getState() == Thread.State.NEW); 55 assertFalse(thread1.getName().isEmpty()); 56 assertTrue(thread1.getThreadGroup() == parent.getThreadGroup()); 57 assertTrue(thread1.isDaemon() == parent.isDaemon()); 58 assertTrue(thread1.getPriority() == parent.getPriority()); 59 assertTrue(thread1.getContextClassLoader() == parent.getContextClassLoader()); 60 thread1.start(); 61 thread1.join(); 62 assertTrue(done1.get()); 63 64 // start 65 AtomicBoolean done2 = new AtomicBoolean(); 66 Thread thread2 = builder.start(() -> done2.set(true)); 67 assertFalse(thread2.isVirtual()); 68 assertTrue(thread2.getState() != Thread.State.NEW); 69 assertFalse(thread2.getName().isEmpty()); 70 ThreadGroup group2 = thread2.getThreadGroup(); 71 assertTrue(group2 == parent.getThreadGroup() || group2 == null); 72 assertTrue(thread2.isDaemon() == parent.isDaemon()); 73 assertTrue(thread2.getPriority() == parent.getPriority()); 74 assertTrue(thread2.getContextClassLoader() == parent.getContextClassLoader()); 75 thread2.join(); 76 assertTrue(done2.get()); 77 78 // factory 79 AtomicBoolean done3 = new AtomicBoolean(); 80 Thread thread3 = builder.factory().newThread(() -> done3.set(true)); 81 assertFalse(thread3.isVirtual()); 82 assertTrue(thread3.getState() == Thread.State.NEW); 83 assertFalse(thread3.getName().isEmpty()); 84 assertTrue(thread3.getThreadGroup() == parent.getThreadGroup()); 85 assertTrue(thread3.isDaemon() == parent.isDaemon()); 86 assertTrue(thread3.getPriority() == parent.getPriority()); 87 assertTrue(thread3.getContextClassLoader() == parent.getContextClassLoader()); 88 thread3.start(); 89 thread3.join(); 90 assertTrue(done3.get()); 91 } 92 93 /** 94 * Test Thread.ofVirtual to create virtual threads. 95 */ 96 @Test 97 void testVirtualThread() throws Exception { 98 Thread parent = Thread.currentThread(); 99 Thread.Builder.OfVirtual builder = Thread.ofVirtual(); 100 101 // unstarted 102 AtomicBoolean done1 = new AtomicBoolean(); 103 Thread thread1 = builder.unstarted(() -> done1.set(true)); 104 assertTrue(thread1.isVirtual()); 105 assertTrue(thread1.getState() == Thread.State.NEW); 106 assertTrue(thread1.getName().isEmpty()); 107 assertTrue(thread1.getContextClassLoader() == parent.getContextClassLoader()); 108 assertTrue(thread1.isDaemon()); 109 assertTrue(thread1.getPriority() == Thread.NORM_PRIORITY); 110 thread1.start(); 111 thread1.join(); 112 assertTrue(done1.get()); 113 114 // start 115 AtomicBoolean done2 = new AtomicBoolean(); 116 Thread thread2 = builder.start(() -> done2.set(true)); 117 assertTrue(thread2.isVirtual()); 118 assertTrue(thread2.getState() != Thread.State.NEW); 119 assertTrue(thread2.getName().isEmpty()); 120 assertTrue(thread2.getContextClassLoader() == parent.getContextClassLoader()); 121 assertTrue(thread2.isDaemon()); 122 assertTrue(thread2.getPriority() == Thread.NORM_PRIORITY); 123 thread2.join(); 124 assertTrue(done2.get()); 125 126 // factory 127 AtomicBoolean done3 = new AtomicBoolean(); 128 Thread thread3 = builder.factory().newThread(() -> done3.set(true)); 129 assertTrue(thread3.isVirtual()); 130 assertTrue(thread3.getState() == Thread.State.NEW); 131 assertTrue(thread3.getName().isEmpty()); 132 assertTrue(thread3.getContextClassLoader() == parent.getContextClassLoader()); 133 assertTrue(thread3.isDaemon()); 134 assertTrue(thread3.getPriority() == Thread.NORM_PRIORITY); 135 thread3.start(); 136 thread3.join(); 137 assertTrue(done3.get()); 138 } 139 140 /** 141 * Test Thread.Builder.name. 142 */ 143 @Test 144 void testName1() { 145 Thread.Builder builder = Thread.ofPlatform().name("duke"); 146 147 Thread thread1 = builder.unstarted(() -> { }); 148 Thread thread2 = builder.start(() -> { }); 149 Thread thread3 = builder.factory().newThread(() -> { }); 150 151 assertTrue(thread1.getName().equals("duke")); 152 assertTrue(thread2.getName().equals("duke")); 153 assertTrue(thread3.getName().equals("duke")); 154 } 155 156 @Test 157 void testName2() { 158 Thread.Builder builder = Thread.ofVirtual().name("duke"); 159 160 Thread thread1 = builder.unstarted(() -> { }); 161 Thread thread2 = builder.start(() -> { }); 162 Thread thread3 = builder.factory().newThread(() -> { }); 163 164 assertTrue(thread1.getName().equals("duke")); 165 assertTrue(thread2.getName().equals("duke")); 166 assertTrue(thread3.getName().equals("duke")); 167 } 168 169 @Test 170 void testName3() { 171 Thread.Builder builder = Thread.ofPlatform().name("duke-", 100); 172 173 Thread thread1 = builder.unstarted(() -> { }); 174 Thread thread2 = builder.unstarted(() -> { }); 175 Thread thread3 = builder.unstarted(() -> { }); 176 177 assertTrue(thread1.getName().equals("duke-100")); 178 assertTrue(thread2.getName().equals("duke-101")); 179 assertTrue(thread3.getName().equals("duke-102")); 180 181 ThreadFactory factory = builder.factory(); 182 Thread thread4 = factory.newThread(() -> { }); 183 Thread thread5 = factory.newThread(() -> { }); 184 Thread thread6 = factory.newThread(() -> { }); 185 186 assertTrue(thread4.getName().equals("duke-103")); 187 assertTrue(thread5.getName().equals("duke-104")); 188 assertTrue(thread6.getName().equals("duke-105")); 189 } 190 191 @Test 192 void testName4() { 193 Thread.Builder builder = Thread.ofVirtual().name("duke-", 100); 194 195 Thread thread1 = builder.unstarted(() -> { }); 196 Thread thread2 = builder.unstarted(() -> { }); 197 Thread thread3 = builder.unstarted(() -> { }); 198 199 assertTrue(thread1.getName().equals("duke-100")); 200 assertTrue(thread2.getName().equals("duke-101")); 201 assertTrue(thread3.getName().equals("duke-102")); 202 203 ThreadFactory factory = builder.factory(); 204 Thread thread4 = factory.newThread(() -> { }); 205 Thread thread5 = factory.newThread(() -> { }); 206 Thread thread6 = factory.newThread(() -> { }); 207 208 assertTrue(thread4.getName().equals("duke-103")); 209 assertTrue(thread5.getName().equals("duke-104")); 210 assertTrue(thread6.getName().equals("duke-105")); 211 } 212 213 /** 214 * Test Thread.Builder.OfPlatform.group. 215 */ 216 @Test 217 void testThreadGroup1() { 218 ThreadGroup group = new ThreadGroup("groupies"); 219 Thread.Builder builder = Thread.ofPlatform().group(group); 220 221 Thread thread1 = builder.unstarted(() -> { }); 222 223 AtomicBoolean done = new AtomicBoolean(); 224 Thread thread2 = builder.start(() -> { 225 while (!done.get()) { 226 LockSupport.park(); 227 } 228 }); 229 230 Thread thread3 = builder.factory().newThread(() -> { }); 231 232 try { 233 assertTrue(thread1.getThreadGroup() == group); 234 assertTrue(thread2.getThreadGroup() == group); 235 assertTrue(thread3.getThreadGroup() == group); 236 } finally { 237 done.set(true); 238 LockSupport.unpark(thread2); 239 } 240 } 241 242 @Test 243 void testThreadGroup2() { 244 ThreadGroup vgroup = Thread.ofVirtual().unstarted(() -> { }).getThreadGroup(); 245 assertEquals("VirtualThreads", vgroup.getName()); 246 247 Thread thread1 = Thread.ofVirtual().unstarted(() -> { }); 248 Thread thread2 = Thread.ofVirtual().start(LockSupport::park); 249 Thread thread3 = Thread.ofVirtual().factory().newThread(() -> { }); 250 251 try { 252 assertTrue(thread1.getThreadGroup() == vgroup); 253 assertTrue(thread2.getThreadGroup() == vgroup); 254 assertTrue(thread3.getThreadGroup() == vgroup); 255 } finally { 256 LockSupport.unpark(thread2); 257 } 258 } 259 260 /** 261 * Test Thread.Builder.OfPlatform.priority. 262 */ 263 @Test 264 void testPriority1() { 265 int priority = Thread.currentThread().getPriority(); 266 267 Thread.Builder builder = Thread.ofPlatform(); 268 Thread thread1 = builder.unstarted(() -> { }); 269 Thread thread2 = builder.start(() -> { }); 270 Thread thread3 = builder.factory().newThread(() -> { }); 271 272 assertTrue(thread1.getPriority() == priority); 273 assertTrue(thread2.getPriority() == priority); 274 assertTrue(thread3.getPriority() == priority); 275 } 276 277 @Test 278 void testPriority2() { 279 int priority = Thread.MIN_PRIORITY; 280 281 Thread.Builder builder = Thread.ofPlatform().priority(priority); 282 Thread thread1 = builder.unstarted(() -> { }); 283 Thread thread2 = builder.start(() -> { }); 284 Thread thread3 = builder.factory().newThread(() -> { }); 285 286 assertTrue(thread1.getPriority() == priority); 287 assertTrue(thread2.getPriority() == priority); 288 assertTrue(thread3.getPriority() == priority); 289 } 290 291 @Test 292 void testPriority3() { 293 Thread currentThread = Thread.currentThread(); 294 assumeFalse(currentThread.isVirtual(), "Main thread is a virtual thread"); 295 296 int maxPriority = currentThread.getThreadGroup().getMaxPriority(); 297 int priority = Math.min(maxPriority + 1, Thread.MAX_PRIORITY); 298 299 Thread.Builder builder = Thread.ofPlatform().priority(priority); 300 Thread thread1 = builder.unstarted(() -> { }); 301 Thread thread2 = builder.start(() -> { }); 302 Thread thread3 = builder.factory().newThread(() -> { }); 303 304 assertTrue(thread1.getPriority() == priority); 305 assertTrue(thread2.getPriority() == priority); 306 assertTrue(thread3.getPriority() == priority); 307 } 308 309 @Test 310 void testPriority4() { 311 var builder = Thread.ofPlatform(); 312 assertThrows(IllegalArgumentException.class, 313 () -> builder.priority(Thread.MIN_PRIORITY - 1)); 314 } 315 316 @Test 317 void testPriority5() { 318 var builder = Thread.ofPlatform(); 319 assertThrows(IllegalArgumentException.class, 320 () -> builder.priority(Thread.MAX_PRIORITY + 1)); 321 } 322 323 /** 324 * Test Thread.Builder.OfPlatform.daemon. 325 */ 326 @Test 327 void testDaemon1() { 328 Thread.Builder builder = Thread.ofPlatform().daemon(false); 329 330 Thread thread1 = builder.unstarted(() -> { }); 331 Thread thread2 = builder.start(() -> { }); 332 Thread thread3 = builder.factory().newThread(() -> { }); 333 334 assertFalse(thread1.isDaemon()); 335 assertFalse(thread2.isDaemon()); 336 assertFalse(thread3.isDaemon()); 337 } 338 339 @Test 340 void testDaemon2() { 341 Thread.Builder builder = Thread.ofPlatform().daemon(true); 342 343 Thread thread1 = builder.unstarted(() -> { }); 344 Thread thread2 = builder.start(() -> { }); 345 Thread thread3 = builder.factory().newThread(() -> { }); 346 347 assertTrue(thread1.isDaemon()); 348 assertTrue(thread2.isDaemon()); 349 assertTrue(thread3.isDaemon()); 350 } 351 352 @Test 353 void testDaemon3() { 354 Thread.Builder builder = Thread.ofPlatform().daemon(); 355 356 Thread thread1 = builder.unstarted(() -> { }); 357 Thread thread2 = builder.start(() -> { }); 358 Thread thread3 = builder.factory().newThread(() -> { }); 359 360 assertTrue(thread1.isDaemon()); 361 assertTrue(thread2.isDaemon()); 362 assertTrue(thread3.isDaemon()); 363 } 364 365 @Test 366 void testDaemon4() { 367 Thread.Builder builder = Thread.ofPlatform(); 368 369 Thread thread1 = builder.unstarted(() -> { }); 370 Thread thread2 = builder.start(() -> { }); 371 Thread thread3 = builder.factory().newThread(() -> { }); 372 373 // daemon status should be inherited 374 boolean d = Thread.currentThread().isDaemon(); 375 assertTrue(thread1.isDaemon() == d); 376 assertTrue(thread2.isDaemon() == d); 377 assertTrue(thread3.isDaemon() == d); 378 } 379 380 /** 381 * Test Thread.ofVirtual creates daemon threads. 382 */ 383 @Test 384 void testDaemon5() { 385 Thread.Builder builder = Thread.ofVirtual(); 386 387 Thread thread1 = builder.unstarted(() -> { }); 388 Thread thread2 = builder.start(() -> { }); 389 Thread thread3 = builder.factory().newThread(() -> { }); 390 391 // daemon status should always be true 392 assertTrue(thread1.isDaemon()); 393 assertTrue(thread2.isDaemon()); 394 assertTrue(thread3.isDaemon()); 395 } 396 397 /** 398 * Test Thread.Builder.OfPlatform.stackSize. 399 */ 400 @Test 401 void testStackSize1() { 402 Thread.Builder builder = Thread.ofPlatform().stackSize(1024*1024); 403 Thread thread1 = builder.unstarted(() -> { }); 404 Thread thread2 = builder.start(() -> { }); 405 Thread thread3 = builder.factory().newThread(() -> { }); 406 } 407 408 @Test 409 void testStackSize2() { 410 Thread.Builder builder = Thread.ofPlatform().stackSize(0); 411 Thread thread1 = builder.unstarted(() -> { }); 412 Thread thread2 = builder.start(() -> { }); 413 Thread thread3 = builder.factory().newThread(() -> { }); 414 } 415 416 @Test 417 void testStackSize3() { 418 var builder = Thread.ofPlatform(); 419 assertThrows(IllegalArgumentException.class, () -> builder.stackSize(-1)); 420 } 421 422 /** 423 * Test Thread.Builder.uncaughtExceptionHandler. 424 */ 425 @Test 426 void testUncaughtExceptionHandler1() throws Exception { 427 class FooException extends RuntimeException { } 428 AtomicReference<Thread> threadRef = new AtomicReference<>(); 429 AtomicReference<Throwable> exceptionRef = new AtomicReference<>(); 430 Thread thread = Thread.ofPlatform() 431 .uncaughtExceptionHandler((t, e) -> { 432 assertTrue(t == Thread.currentThread()); 433 threadRef.set(t); 434 exceptionRef.set(e); 435 }) 436 .start(() -> { throw new FooException(); }); 437 thread.join(); 438 assertTrue(threadRef.get() == thread); 439 assertTrue(exceptionRef.get() instanceof FooException); 440 } 441 442 @Test 443 void testUncaughtExceptionHandler2() throws Exception { 444 class FooException extends RuntimeException { } 445 AtomicReference<Thread> threadRef = new AtomicReference<>(); 446 AtomicReference<Throwable> exceptionRef = new AtomicReference<>(); 447 Thread thread = Thread.ofVirtual() 448 .uncaughtExceptionHandler((t, e) -> { 449 assertTrue(t == Thread.currentThread()); 450 threadRef.set(t); 451 exceptionRef.set(e); 452 }) 453 .start(() -> { throw new FooException(); }); 454 thread.join(); 455 assertTrue(threadRef.get() == thread); 456 assertTrue(exceptionRef.get() instanceof FooException); 457 } 458 459 @Test 460 void testUncaughtExceptionHandler3() throws Exception { 461 class FooException extends RuntimeException { } 462 AtomicReference<Thread> threadRef = new AtomicReference<>(); 463 AtomicReference<Throwable> exceptionRef = new AtomicReference<>(); 464 Thread thread = Thread.ofPlatform() 465 .uncaughtExceptionHandler((t, e) -> { 466 assertTrue(t == Thread.currentThread()); 467 threadRef.set(t); 468 exceptionRef.set(e); 469 }) 470 .factory() 471 .newThread(() -> { throw new FooException(); }); 472 thread.start(); 473 thread.join(); 474 assertTrue(threadRef.get() == thread); 475 assertTrue(exceptionRef.get() instanceof FooException); 476 } 477 478 @Test 479 void testUncaughtExceptionHandler4() throws Exception { 480 class FooException extends RuntimeException { } 481 AtomicReference<Thread> threadRef = new AtomicReference<>(); 482 AtomicReference<Throwable> exceptionRef = new AtomicReference<>(); 483 Thread thread = Thread.ofPlatform() 484 .uncaughtExceptionHandler((t, e) -> { 485 assertTrue(t == Thread.currentThread()); 486 threadRef.set(t); 487 exceptionRef.set(e); 488 }) 489 .factory() 490 .newThread(() -> { throw new FooException(); }); 491 thread.start(); 492 thread.join(); 493 assertTrue(threadRef.get() == thread); 494 assertTrue(exceptionRef.get() instanceof FooException); 495 } 496 497 static final ThreadLocal<Object> LOCAL = new ThreadLocal<>(); 498 static final ThreadLocal<Object> INHERITED_LOCAL = new InheritableThreadLocal<>(); 499 500 /** 501 * Tests that a builder creates threads that support thread locals 502 */ 503 private void testThreadLocals(Thread.Builder builder) throws Exception { 504 AtomicBoolean done = new AtomicBoolean(); 505 Runnable task = () -> { 506 Object value = new Object(); 507 LOCAL.set(value); 508 assertTrue(LOCAL.get() == value); 509 done.set(true); 510 }; 511 512 done.set(false); 513 Thread thread1 = builder.unstarted(task); 514 thread1.start(); 515 thread1.join(); 516 assertTrue(done.get()); 517 518 done.set(false); 519 Thread thread2 = builder.start(task); 520 thread2.join(); 521 assertTrue(done.get()); 522 523 done.set(false); 524 Thread thread3 = builder.factory().newThread(task); 525 thread3.start(); 526 thread3.join(); 527 assertTrue(done.get()); 528 } 529 530 /** 531 * Tests that a builder creates threads that do not support thread locals 532 */ 533 private void testNoThreadLocals(Thread.Builder builder) throws Exception { 534 AtomicBoolean done = new AtomicBoolean(); 535 Runnable task = () -> { 536 try { 537 LOCAL.set(new Object()); 538 } catch (UnsupportedOperationException expected) { 539 done.set(true); 540 } 541 }; 542 543 done.set(false); 544 Thread thread1 = builder.unstarted(task); 545 thread1.start(); 546 thread1.join(); 547 assertTrue(done.get()); 548 549 done.set(false); 550 Thread thread2 = builder.start(task); 551 thread2.join(); 552 assertTrue(done.get()); 553 554 done.set(false); 555 Thread thread3 = builder.factory().newThread(task); 556 thread3.start(); 557 thread3.join(); 558 assertTrue(done.get()); 559 } 560 561 /** 562 * Test Thread.Builder creates threads that allow thread locals. 563 */ 564 @Test 565 void testThreadLocals1() throws Exception { 566 Thread.Builder builder = Thread.ofPlatform(); 567 testThreadLocals(builder); 568 } 569 570 @Test 571 void testThreadLocals2() throws Exception { 572 Thread.Builder builder = Thread.ofVirtual(); 573 testThreadLocals(builder); 574 } 575 576 /** 577 * Test Thread.Builder creating threads that disallow or allow 578 * thread locals. 579 */ 580 @Test 581 void testThreadLocals3() throws Exception { 582 Thread.Builder builder = Thread.ofPlatform(); 583 584 // disallow 585 builder.allowSetThreadLocals(false); 586 testNoThreadLocals(builder); 587 588 // allow 589 builder.allowSetThreadLocals(true); 590 testThreadLocals(builder); 591 } 592 593 @Test 594 void testThreadLocals4() throws Exception { 595 Thread.Builder builder = Thread.ofVirtual(); 596 597 // disallow 598 builder.allowSetThreadLocals(false); 599 testNoThreadLocals(builder); 600 601 // allow 602 builder.allowSetThreadLocals(true); 603 testThreadLocals(builder); 604 } 605 606 /** 607 * Tests that a builder creates threads that inherits the initial values of 608 * inheritable thread locals. 609 */ 610 private void testInheritedThreadLocals(Thread.Builder builder) throws Exception { 611 Object value = new Object(); 612 INHERITED_LOCAL.set(value); 613 614 AtomicBoolean done = new AtomicBoolean(); 615 Runnable task = () -> { 616 assertTrue(INHERITED_LOCAL.get() == value); 617 done.set(true); 618 }; 619 620 done.set(false); 621 Thread thread1 = builder.unstarted(task); 622 thread1.start(); 623 thread1.join(); 624 assertTrue(done.get()); 625 626 done.set(false); 627 Thread thread2 = builder.start(task); 628 thread2.join(); 629 assertTrue(done.get()); 630 631 done.set(false); 632 Thread thread3 = builder.factory().newThread(task); 633 thread3.start(); 634 thread3.join(); 635 assertTrue(done.get()); 636 } 637 638 /** 639 * Tests that a builder creates threads that do not inherit the initial values 640 * of inheritable thread locals. 641 */ 642 private void testNoInheritedThreadLocals(Thread.Builder builder) throws Exception { 643 Object value = new Object(); 644 INHERITED_LOCAL.set(value); 645 646 AtomicBoolean done = new AtomicBoolean(); 647 Runnable task = () -> { 648 assertNull(INHERITED_LOCAL.get()); 649 done.set(true); 650 }; 651 652 done.set(false); 653 Thread thread1 = builder.unstarted(task); 654 thread1.start(); 655 thread1.join(); 656 assertTrue(done.get()); 657 658 done.set(false); 659 Thread thread2 = builder.start(task); 660 thread2.join(); 661 assertTrue(done.get()); 662 663 done.set(false); 664 Thread thread3 = builder.factory().newThread(task); 665 thread3.start(); 666 thread3.join(); 667 assertTrue(done.get()); 668 } 669 670 /** 671 * Test Thread.Builder creating threads that inherit or do not inherit 672 * the initial values of inheritable thread locals. 673 */ 674 @Test 675 void testInheritedThreadLocals1() throws Exception { 676 Thread.Builder builder = Thread.ofPlatform(); 677 testInheritedThreadLocals(builder); // default 678 679 // do no inherit 680 builder.inheritInheritableThreadLocals(false); 681 testNoInheritedThreadLocals(builder); 682 683 // inherit 684 builder.inheritInheritableThreadLocals(true); 685 testInheritedThreadLocals(builder); 686 } 687 688 @Test 689 void testInheritedThreadLocals2() throws Exception { 690 Thread.Builder builder = Thread.ofVirtual(); 691 testInheritedThreadLocals(builder); // default 692 693 // do no inherit 694 builder.inheritInheritableThreadLocals(false); 695 testNoInheritedThreadLocals(builder); 696 697 // inherit 698 builder.inheritInheritableThreadLocals(true); 699 testInheritedThreadLocals(builder); 700 } 701 702 @Test 703 void testInheritedThreadLocals3() throws Exception { 704 Thread.Builder builder = Thread.ofPlatform(); 705 706 // thread locals not allowed 707 builder.allowSetThreadLocals(false); 708 testNoInheritedThreadLocals(builder); 709 builder.inheritInheritableThreadLocals(false); 710 testNoInheritedThreadLocals(builder); 711 builder.inheritInheritableThreadLocals(true); 712 testNoInheritedThreadLocals(builder); 713 714 // thread locals allowed 715 builder.allowSetThreadLocals(true); 716 builder.inheritInheritableThreadLocals(false); 717 testNoInheritedThreadLocals(builder); 718 builder.inheritInheritableThreadLocals(true); 719 testInheritedThreadLocals(builder); 720 } 721 722 @Test 723 void testInheritedThreadLocals4() throws Exception { 724 Thread.Builder builder = Thread.ofVirtual(); 725 726 // thread locals not allowed 727 builder.allowSetThreadLocals(false); 728 testNoInheritedThreadLocals(builder); 729 builder.inheritInheritableThreadLocals(false); 730 testNoInheritedThreadLocals(builder); 731 builder.inheritInheritableThreadLocals(true); 732 testNoInheritedThreadLocals(builder); 733 734 // thread locals allowed 735 builder.allowSetThreadLocals(true); 736 builder.inheritInheritableThreadLocals(false); 737 testNoInheritedThreadLocals(builder); 738 builder.inheritInheritableThreadLocals(true); 739 testInheritedThreadLocals(builder); 740 } 741 742 /** 743 * Tests a builder creates threads that inherit the context class loader. 744 */ 745 private void testInheritContextClassLoader(Thread.Builder builder) throws Exception { 746 ClassLoader savedCCL = Thread.currentThread().getContextClassLoader(); 747 try { 748 ClassLoader loader = new ClassLoader() { }; 749 Thread.currentThread().setContextClassLoader(loader); 750 751 var ref = new AtomicReference<ClassLoader>(); 752 Runnable task = () -> { 753 ref.set(Thread.currentThread().getContextClassLoader()); 754 }; 755 756 // unstarted 757 Thread thread1 = builder.unstarted(task); 758 assertTrue(thread1.getContextClassLoader() == loader); 759 760 // started 761 ref.set(null); 762 thread1.start(); 763 thread1.join(); 764 assertTrue(ref.get() == loader); 765 766 // factory 767 Thread thread2 = builder.factory().newThread(task); 768 assertTrue(thread2.getContextClassLoader() == loader); 769 770 // started 771 ref.set(null); 772 thread2.start(); 773 thread2.join(); 774 assertTrue(ref.get() == loader); 775 776 } finally { 777 Thread.currentThread().setContextClassLoader(savedCCL); 778 } 779 } 780 781 /** 782 * Tests a builder creates threads does not inherit the context class loader. 783 */ 784 private void testNoInheritContextClassLoader(Thread.Builder builder) throws Exception { 785 ClassLoader savedCCL = Thread.currentThread().getContextClassLoader(); 786 try { 787 Thread.currentThread().setContextClassLoader( new ClassLoader() { }); 788 789 ClassLoader scl = ClassLoader.getSystemClassLoader(); 790 791 var ref = new AtomicReference<ClassLoader>(); 792 Runnable task = () -> { 793 ref.set(Thread.currentThread().getContextClassLoader()); 794 }; 795 796 // unstarted 797 Thread thread1 = builder.unstarted(task); 798 assertTrue(thread1.getContextClassLoader() == scl); 799 800 // started 801 ref.set(null); 802 thread1.start(); 803 thread1.join(); 804 assertTrue(ref.get() == scl); 805 806 // factory 807 Thread thread2 = builder.factory().newThread(task); 808 assertTrue(thread2.getContextClassLoader() == scl); 809 810 // started 811 ref.set(null); 812 thread2.start(); 813 thread2.join(); 814 assertTrue(ref.get() == scl); 815 816 } finally { 817 Thread.currentThread().setContextClassLoader(savedCCL); 818 } 819 } 820 821 /** 822 * Test Thread.Builder creating threads that inherit or do not inherit 823 * the thread context class loader. 824 */ 825 @Test 826 void testContextClassLoader1() throws Exception { 827 Thread.Builder builder = Thread.ofPlatform(); 828 testInheritContextClassLoader(builder); // default 829 830 // do no inherit 831 builder.inheritInheritableThreadLocals(false); 832 testNoInheritContextClassLoader(builder); 833 834 // inherit 835 builder.inheritInheritableThreadLocals(true); 836 testInheritContextClassLoader(builder); 837 } 838 839 @Test 840 void testContextClassLoader2() throws Exception { 841 Thread.Builder builder = Thread.ofVirtual(); 842 testInheritContextClassLoader(builder); // default 843 844 // do no inherit 845 builder.inheritInheritableThreadLocals(false); 846 testNoInheritContextClassLoader(builder); 847 848 // inherit 849 builder.inheritInheritableThreadLocals(true); 850 testInheritContextClassLoader(builder); 851 } 852 853 @Test 854 void testContextClassLoader3() throws Exception { 855 Thread.Builder builder = Thread.ofPlatform(); 856 857 // thread locals not allowed 858 builder.allowSetThreadLocals(false); 859 testNoInheritContextClassLoader(builder); 860 builder.inheritInheritableThreadLocals(false); 861 testNoInheritContextClassLoader(builder); 862 builder.inheritInheritableThreadLocals(true); 863 testNoInheritContextClassLoader(builder); 864 865 // thread locals allowed 866 builder.allowSetThreadLocals(true); 867 builder.inheritInheritableThreadLocals(false); 868 testNoInheritContextClassLoader(builder); 869 builder.inheritInheritableThreadLocals(true); 870 testInheritContextClassLoader(builder); 871 } 872 873 @Test 874 void testContextClassLoader4() throws Exception { 875 Thread.Builder builder = Thread.ofVirtual(); 876 877 // thread locals not allowed 878 builder.allowSetThreadLocals(false); 879 testNoInheritContextClassLoader(builder); 880 builder.inheritInheritableThreadLocals(false); 881 testNoInheritContextClassLoader(builder); 882 builder.inheritInheritableThreadLocals(true); 883 testNoInheritContextClassLoader(builder); 884 885 // thread locals allowed 886 builder.allowSetThreadLocals(true); 887 builder.inheritInheritableThreadLocals(false); 888 testNoInheritContextClassLoader(builder); 889 builder.inheritInheritableThreadLocals(true); 890 testInheritContextClassLoader(builder); 891 } 892 893 /** 894 * Test NullPointerException. 895 */ 896 @Test 897 void testNulls1() { 898 Thread.Builder.OfPlatform builder = Thread.ofPlatform(); 899 assertThrows(NullPointerException.class, () -> builder.group(null)); 900 assertThrows(NullPointerException.class, () -> builder.name(null)); 901 assertThrows(NullPointerException.class, () -> builder.name(null, 0)); 902 assertThrows(NullPointerException.class, () -> builder.uncaughtExceptionHandler(null)); 903 assertThrows(NullPointerException.class, () -> builder.unstarted(null)); 904 assertThrows(NullPointerException.class, () -> builder.start(null)); 905 } 906 907 @Test 908 void testNulls2() { 909 Thread.Builder builder = Thread.ofVirtual(); 910 assertThrows(NullPointerException.class, () -> builder.name(null)); 911 assertThrows(NullPointerException.class, () -> builder.name(null, 0)); 912 assertThrows(NullPointerException.class, () -> builder.uncaughtExceptionHandler(null)); 913 assertThrows(NullPointerException.class, () -> builder.unstarted(null)); 914 assertThrows(NullPointerException.class, () -> builder.start(null)); 915 } 916 }