| /* | |
| * Copyright (c) 2019, 2023, Oracle and/or its affiliates. All rights reserved. | |
| * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. | |
| * | |
| * This code is free software; you can redistribute it and/or modify it | |
| * under the terms of the GNU General Public License version 2 only, as | |
| * published by the Free Software Foundation. | |
| * | |
| * This code is distributed in the hope that it will be useful, but WITHOUT | |
| * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | |
| * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License | |
| * version 2 for more details (a copy is included in the LICENSE file that | |
| * accompanied this code). | |
| * | |
| * You should have received a copy of the GNU General Public License version | |
| * 2 along with this work; if not, write to the Free Software Foundation, | |
| * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. | |
| * | |
| * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA | |
| * or visit www.oracle.com if you need additional information or have any | |
| * questions. | |
| */ | |
| /** | |
| * @test | |
| * @summary Unit test for Thread.Builder | |
| * @run junit BuilderTest | |
| */ | |
| import java.util.concurrent.*; | |
| import java.util.concurrent.atomic.AtomicBoolean; | |
| import java.util.concurrent.atomic.AtomicReference; | |
| import java.util.concurrent.locks.LockSupport; | |
| import org.junit.jupiter.api.Test; | |
| import static org.junit.jupiter.api.Assertions.*; | |
| import static org.junit.jupiter.api.Assumptions.*; | |
| class BuilderTest { | |
| /** | |
| * Test Thread.ofPlatform to create platform threads. | |
| */ | |
| @Test | |
| void testPlatformThread() throws Exception { | |
| Thread parent = Thread.currentThread(); | |
| Thread.Builder.OfPlatform builder = Thread.ofPlatform(); | |
| // unstarted | |
| AtomicBoolean done1 = new AtomicBoolean(); | |
| Thread thread1 = builder.unstarted(() -> done1.set(true)); | |
| assertFalse(thread1.isVirtual()); | |
| assertTrue(thread1.getState() == Thread.State.NEW); | |
| assertFalse(thread1.getName().isEmpty()); | |
| assertTrue(thread1.getThreadGroup() == parent.getThreadGroup()); | |
| assertTrue(thread1.isDaemon() == parent.isDaemon()); | |
| assertTrue(thread1.getPriority() == parent.getPriority()); | |
| assertTrue(thread1.getContextClassLoader() == parent.getContextClassLoader()); | |
| thread1.start(); | |
| thread1.join(); | |
| assertTrue(done1.get()); | |
| // start | |
| AtomicBoolean done2 = new AtomicBoolean(); | |
| Thread thread2 = builder.start(() -> done2.set(true)); | |
| assertFalse(thread2.isVirtual()); | |
| assertTrue(thread2.getState() != Thread.State.NEW); | |
| assertFalse(thread2.getName().isEmpty()); | |
| ThreadGroup group2 = thread2.getThreadGroup(); | |
| assertTrue(group2 == parent.getThreadGroup() || group2 == null); | |
| assertTrue(thread2.isDaemon() == parent.isDaemon()); | |
| assertTrue(thread2.getPriority() == parent.getPriority()); | |
| assertTrue(thread2.getContextClassLoader() == parent.getContextClassLoader()); | |
| thread2.join(); | |
| assertTrue(done2.get()); | |
| // factory | |
| AtomicBoolean done3 = new AtomicBoolean(); | |
| Thread thread3 = builder.factory().newThread(() -> done3.set(true)); | |
| assertFalse(thread3.isVirtual()); | |
| assertTrue(thread3.getState() == Thread.State.NEW); | |
| assertFalse(thread3.getName().isEmpty()); | |
| assertTrue(thread3.getThreadGroup() == parent.getThreadGroup()); | |
| assertTrue(thread3.isDaemon() == parent.isDaemon()); | |
| assertTrue(thread3.getPriority() == parent.getPriority()); | |
| assertTrue(thread3.getContextClassLoader() == parent.getContextClassLoader()); | |
| thread3.start(); | |
| thread3.join(); | |
| assertTrue(done3.get()); | |
| } | |
| /** | |
| * Test Thread.ofVirtual to create virtual threads. | |
| */ | |
| @Test | |
| void testVirtualThread() throws Exception { | |
| Thread parent = Thread.currentThread(); | |
| Thread.Builder.OfVirtual builder = Thread.ofVirtual(); | |
| // unstarted | |
| AtomicBoolean done1 = new AtomicBoolean(); | |
| Thread thread1 = builder.unstarted(() -> done1.set(true)); | |
| assertTrue(thread1.isVirtual()); | |
| assertTrue(thread1.getState() == Thread.State.NEW); | |
| assertTrue(thread1.getName().isEmpty()); | |
| assertTrue(thread1.getContextClassLoader() == parent.getContextClassLoader()); | |
| assertTrue(thread1.isDaemon()); | |
| assertTrue(thread1.getPriority() == Thread.NORM_PRIORITY); | |
| thread1.start(); | |
| thread1.join(); | |
| assertTrue(done1.get()); | |
| // start | |
| AtomicBoolean done2 = new AtomicBoolean(); | |
| Thread thread2 = builder.start(() -> done2.set(true)); | |
| assertTrue(thread2.isVirtual()); | |
| assertTrue(thread2.getState() != Thread.State.NEW); | |
| assertTrue(thread2.getName().isEmpty()); | |
| assertTrue(thread2.getContextClassLoader() == parent.getContextClassLoader()); | |
| assertTrue(thread2.isDaemon()); | |
| assertTrue(thread2.getPriority() == Thread.NORM_PRIORITY); | |
| thread2.join(); | |
| assertTrue(done2.get()); | |
| // factory | |
| AtomicBoolean done3 = new AtomicBoolean(); | |
| Thread thread3 = builder.factory().newThread(() -> done3.set(true)); | |
| assertTrue(thread3.isVirtual()); | |
| assertTrue(thread3.getState() == Thread.State.NEW); | |
| assertTrue(thread3.getName().isEmpty()); | |
| assertTrue(thread3.getContextClassLoader() == parent.getContextClassLoader()); | |
| assertTrue(thread3.isDaemon()); | |
| assertTrue(thread3.getPriority() == Thread.NORM_PRIORITY); | |
| thread3.start(); | |
| thread3.join(); | |
| assertTrue(done3.get()); | |
| } | |
| /** | |
| * Test Thread.Builder.name. | |
| */ | |
| @Test | |
| void testName1() { | |
| Thread.Builder builder = Thread.ofPlatform().name("duke"); | |
| Thread thread1 = builder.unstarted(() -> { }); | |
| Thread thread2 = builder.start(() -> { }); | |
| Thread thread3 = builder.factory().newThread(() -> { }); | |
| assertTrue(thread1.getName().equals("duke")); | |
| assertTrue(thread2.getName().equals("duke")); | |
| assertTrue(thread3.getName().equals("duke")); | |
| } | |
| @Test | |
| void testName2() { | |
| Thread.Builder builder = Thread.ofVirtual().name("duke"); | |
| Thread thread1 = builder.unstarted(() -> { }); | |
| Thread thread2 = builder.start(() -> { }); | |
| Thread thread3 = builder.factory().newThread(() -> { }); | |
| assertTrue(thread1.getName().equals("duke")); | |
| assertTrue(thread2.getName().equals("duke")); | |
| assertTrue(thread3.getName().equals("duke")); | |
| } | |
| @Test | |
| void testName3() { | |
| Thread.Builder builder = Thread.ofPlatform().name("duke-", 100); | |
| Thread thread1 = builder.unstarted(() -> { }); | |
| Thread thread2 = builder.unstarted(() -> { }); | |
| Thread thread3 = builder.unstarted(() -> { }); | |
| assertTrue(thread1.getName().equals("duke-100")); | |
| assertTrue(thread2.getName().equals("duke-101")); | |
| assertTrue(thread3.getName().equals("duke-102")); | |
| ThreadFactory factory = builder.factory(); | |
| Thread thread4 = factory.newThread(() -> { }); | |
| Thread thread5 = factory.newThread(() -> { }); | |
| Thread thread6 = factory.newThread(() -> { }); | |
| assertTrue(thread4.getName().equals("duke-103")); | |
| assertTrue(thread5.getName().equals("duke-104")); | |
| assertTrue(thread6.getName().equals("duke-105")); | |
| } | |
| @Test | |
| void testName4() { | |
| Thread.Builder builder = Thread.ofVirtual().name("duke-", 100); | |
| Thread thread1 = builder.unstarted(() -> { }); | |
| Thread thread2 = builder.unstarted(() -> { }); | |
| Thread thread3 = builder.unstarted(() -> { }); | |
| assertTrue(thread1.getName().equals("duke-100")); | |
| assertTrue(thread2.getName().equals("duke-101")); | |
| assertTrue(thread3.getName().equals("duke-102")); | |
| ThreadFactory factory = builder.factory(); | |
| Thread thread4 = factory.newThread(() -> { }); | |
| Thread thread5 = factory.newThread(() -> { }); | |
| Thread thread6 = factory.newThread(() -> { }); | |
| assertTrue(thread4.getName().equals("duke-103")); | |
| assertTrue(thread5.getName().equals("duke-104")); | |
| assertTrue(thread6.getName().equals("duke-105")); | |
| } | |
| /** | |
| * Test Thread.Builder.OfPlatform.group. | |
| */ | |
| @Test | |
| void testThreadGroup1() { | |
| ThreadGroup group = new ThreadGroup("groupies"); | |
| Thread.Builder builder = Thread.ofPlatform().group(group); | |
| Thread thread1 = builder.unstarted(() -> { }); | |
| AtomicBoolean done = new AtomicBoolean(); | |
| Thread thread2 = builder.start(() -> { | |
| while (!done.get()) { | |
| LockSupport.park(); | |
| } | |
| }); | |
| Thread thread3 = builder.factory().newThread(() -> { }); | |
| try { | |
| assertTrue(thread1.getThreadGroup() == group); | |
| assertTrue(thread2.getThreadGroup() == group); | |
| assertTrue(thread3.getThreadGroup() == group); | |
| } finally { | |
| done.set(true); | |
| LockSupport.unpark(thread2); | |
| } | |
| } | |
| @Test | |
| void testThreadGroup2() { | |
| ThreadGroup vgroup = Thread.ofVirtual().unstarted(() -> { }).getThreadGroup(); | |
| assertEquals("VirtualThreads", vgroup.getName()); | |
| Thread thread1 = Thread.ofVirtual().unstarted(() -> { }); | |
| Thread thread2 = Thread.ofVirtual().start(LockSupport::park); | |
| Thread thread3 = Thread.ofVirtual().factory().newThread(() -> { }); | |
| try { | |
| assertTrue(thread1.getThreadGroup() == vgroup); | |
| assertTrue(thread2.getThreadGroup() == vgroup); | |
| assertTrue(thread3.getThreadGroup() == vgroup); | |
| } finally { | |
| LockSupport.unpark(thread2); | |
| } | |
| } | |
| /** | |
| * Test Thread.Builder.OfPlatform.priority. | |
| */ | |
| @Test | |
| void testPriority1() { | |
| int priority = Thread.currentThread().getPriority(); | |
| Thread.Builder builder = Thread.ofPlatform(); | |
| Thread thread1 = builder.unstarted(() -> { }); | |
| Thread thread2 = builder.start(() -> { }); | |
| Thread thread3 = builder.factory().newThread(() -> { }); | |
| assertTrue(thread1.getPriority() == priority); | |
| assertTrue(thread2.getPriority() == priority); | |
| assertTrue(thread3.getPriority() == priority); | |
| } | |
| @Test | |
| void testPriority2() { | |
| int priority = Thread.MIN_PRIORITY; | |
| Thread.Builder builder = Thread.ofPlatform().priority(priority); | |
| Thread thread1 = builder.unstarted(() -> { }); | |
| Thread thread2 = builder.start(() -> { }); | |
| Thread thread3 = builder.factory().newThread(() -> { }); | |
| assertTrue(thread1.getPriority() == priority); | |
| assertTrue(thread2.getPriority() == priority); | |
| assertTrue(thread3.getPriority() == priority); | |
| } | |
| @Test | |
| void testPriority3() { | |
| Thread currentThread = Thread.currentThread(); | |
| assumeFalse(currentThread.isVirtual(), "Main thread is a virtual thread"); | |
| int maxPriority = currentThread.getThreadGroup().getMaxPriority(); | |
| int priority = Math.min(maxPriority + 1, Thread.MAX_PRIORITY); | |
| Thread.Builder builder = Thread.ofPlatform().priority(priority); | |
| Thread thread1 = builder.unstarted(() -> { }); | |
| Thread thread2 = builder.start(() -> { }); | |
| Thread thread3 = builder.factory().newThread(() -> { }); | |
| assertTrue(thread1.getPriority() == priority); | |
| assertTrue(thread2.getPriority() == priority); | |
| assertTrue(thread3.getPriority() == priority); | |
| } | |
| @Test | |
| void testPriority4() { | |
| var builder = Thread.ofPlatform(); | |
| assertThrows(IllegalArgumentException.class, | |
| () -> builder.priority(Thread.MIN_PRIORITY - 1)); | |
| } | |
| @Test | |
| void testPriority5() { | |
| var builder = Thread.ofPlatform(); | |
| assertThrows(IllegalArgumentException.class, | |
| () -> builder.priority(Thread.MAX_PRIORITY + 1)); | |
| } | |
| /** | |
| * Test Thread.Builder.OfPlatform.daemon. | |
| */ | |
| @Test | |
| void testDaemon1() { | |
| Thread.Builder builder = Thread.ofPlatform().daemon(false); | |
| Thread thread1 = builder.unstarted(() -> { }); | |
| Thread thread2 = builder.start(() -> { }); | |
| Thread thread3 = builder.factory().newThread(() -> { }); | |
| assertFalse(thread1.isDaemon()); | |
| assertFalse(thread2.isDaemon()); | |
| assertFalse(thread3.isDaemon()); | |
| } | |
| @Test | |
| void testDaemon2() { | |
| Thread.Builder builder = Thread.ofPlatform().daemon(true); | |
| Thread thread1 = builder.unstarted(() -> { }); | |
| Thread thread2 = builder.start(() -> { }); | |
| Thread thread3 = builder.factory().newThread(() -> { }); | |
| assertTrue(thread1.isDaemon()); | |
| assertTrue(thread2.isDaemon()); | |
| assertTrue(thread3.isDaemon()); | |
| } | |
| @Test | |
| void testDaemon3() { | |
| Thread.Builder builder = Thread.ofPlatform().daemon(); | |
| Thread thread1 = builder.unstarted(() -> { }); | |
| Thread thread2 = builder.start(() -> { }); | |
| Thread thread3 = builder.factory().newThread(() -> { }); | |
| assertTrue(thread1.isDaemon()); | |
| assertTrue(thread2.isDaemon()); | |
| assertTrue(thread3.isDaemon()); | |
| } | |
| @Test | |
| void testDaemon4() { | |
| Thread.Builder builder = Thread.ofPlatform(); | |
| Thread thread1 = builder.unstarted(() -> { }); | |
| Thread thread2 = builder.start(() -> { }); | |
| Thread thread3 = builder.factory().newThread(() -> { }); | |
| // daemon status should be inherited | |
| boolean d = Thread.currentThread().isDaemon(); | |
| assertTrue(thread1.isDaemon() == d); | |
| assertTrue(thread2.isDaemon() == d); | |
| assertTrue(thread3.isDaemon() == d); | |
| } | |
| /** | |
| * Test Thread.ofVirtual creates daemon threads. | |
| */ | |
| @Test | |
| void testDaemon5() { | |
| Thread.Builder builder = Thread.ofVirtual(); | |
| Thread thread1 = builder.unstarted(() -> { }); | |
| Thread thread2 = builder.start(() -> { }); | |
| Thread thread3 = builder.factory().newThread(() -> { }); | |
| // daemon status should always be true | |
| assertTrue(thread1.isDaemon()); | |
| assertTrue(thread2.isDaemon()); | |
| assertTrue(thread3.isDaemon()); | |
| } | |
| /** | |
| * Test Thread.Builder.OfPlatform.stackSize. | |
| */ | |
| @Test | |
| void testStackSize1() { | |
| Thread.Builder builder = Thread.ofPlatform().stackSize(1024*1024); | |
| Thread thread1 = builder.unstarted(() -> { }); | |
| Thread thread2 = builder.start(() -> { }); | |
| Thread thread3 = builder.factory().newThread(() -> { }); | |
| } | |
| @Test | |
| void testStackSize2() { | |
| Thread.Builder builder = Thread.ofPlatform().stackSize(0); | |
| Thread thread1 = builder.unstarted(() -> { }); | |
| Thread thread2 = builder.start(() -> { }); | |
| Thread thread3 = builder.factory().newThread(() -> { }); | |
| } | |
| @Test | |
| void testStackSize3() { | |
| var builder = Thread.ofPlatform(); | |
| assertThrows(IllegalArgumentException.class, () -> builder.stackSize(-1)); | |
| } | |
| /** | |
| * Test Thread.Builder.uncaughtExceptionHandler. | |
| */ | |
| @Test | |
| void testUncaughtExceptionHandler1() throws Exception { | |
| class FooException extends RuntimeException { } | |
| AtomicReference<Thread> threadRef = new AtomicReference<>(); | |
| AtomicReference<Throwable> exceptionRef = new AtomicReference<>(); | |
| Thread thread = Thread.ofPlatform() | |
| .uncaughtExceptionHandler((t, e) -> { | |
| assertTrue(t == Thread.currentThread()); | |
| threadRef.set(t); | |
| exceptionRef.set(e); | |
| }) | |
| .start(() -> { throw new FooException(); }); | |
| thread.join(); | |
| assertTrue(threadRef.get() == thread); | |
| assertTrue(exceptionRef.get() instanceof FooException); | |
| } | |
| @Test | |
| void testUncaughtExceptionHandler2() throws Exception { | |
| class FooException extends RuntimeException { } | |
| AtomicReference<Thread> threadRef = new AtomicReference<>(); | |
| AtomicReference<Throwable> exceptionRef = new AtomicReference<>(); | |
| Thread thread = Thread.ofVirtual() | |
| .uncaughtExceptionHandler((t, e) -> { | |
| assertTrue(t == Thread.currentThread()); | |
| threadRef.set(t); | |
| exceptionRef.set(e); | |
| }) | |
| .start(() -> { throw new FooException(); }); | |
| thread.join(); | |
| assertTrue(threadRef.get() == thread); | |
| assertTrue(exceptionRef.get() instanceof FooException); | |
| } | |
| @Test | |
| void testUncaughtExceptionHandler3() throws Exception { | |
| class FooException extends RuntimeException { } | |
| AtomicReference<Thread> threadRef = new AtomicReference<>(); | |
| AtomicReference<Throwable> exceptionRef = new AtomicReference<>(); | |
| Thread thread = Thread.ofPlatform() | |
| .uncaughtExceptionHandler((t, e) -> { | |
| assertTrue(t == Thread.currentThread()); | |
| threadRef.set(t); | |
| exceptionRef.set(e); | |
| }) | |
| .factory() | |
| .newThread(() -> { throw new FooException(); }); | |
| thread.start(); | |
| thread.join(); | |
| assertTrue(threadRef.get() == thread); | |
| assertTrue(exceptionRef.get() instanceof FooException); | |
| } | |
| @Test | |
| void testUncaughtExceptionHandler4() throws Exception { | |
| class FooException extends RuntimeException { } | |
| AtomicReference<Thread> threadRef = new AtomicReference<>(); | |
| AtomicReference<Throwable> exceptionRef = new AtomicReference<>(); | |
| Thread thread = Thread.ofPlatform() | |
| .uncaughtExceptionHandler((t, e) -> { | |
| assertTrue(t == Thread.currentThread()); | |
| threadRef.set(t); | |
| exceptionRef.set(e); | |
| }) | |
| .factory() | |
| .newThread(() -> { throw new FooException(); }); | |
| thread.start(); | |
| thread.join(); | |
| assertTrue(threadRef.get() == thread); | |
| assertTrue(exceptionRef.get() instanceof FooException); | |
| } | |
| static final ThreadLocal<Object> LOCAL = new ThreadLocal<>(); | |
| static final ThreadLocal<Object> INHERITED_LOCAL = new InheritableThreadLocal<>(); | |
| /** | |
| * Tests that a builder creates threads that support thread locals | |
| */ | |
| private void testThreadLocals(Thread.Builder builder) throws Exception { | |
| AtomicBoolean done = new AtomicBoolean(); | |
| Runnable task = () -> { | |
| Object value = new Object(); | |
| LOCAL.set(value); | |
| assertTrue(LOCAL.get() == value); | |
| done.set(true); | |
| }; | |
| done.set(false); | |
| Thread thread1 = builder.unstarted(task); | |
| thread1.start(); | |
| thread1.join(); | |
| assertTrue(done.get()); | |
| done.set(false); | |
| Thread thread2 = builder.start(task); | |
| thread2.join(); | |
| assertTrue(done.get()); | |
| done.set(false); | |
| Thread thread3 = builder.factory().newThread(task); | |
| thread3.start(); | |
| thread3.join(); | |
| assertTrue(done.get()); | |
| } | |
| /** | |
| * Tests that a builder creates threads that do not support thread locals | |
| */ | |
| private void testNoThreadLocals(Thread.Builder builder) throws Exception { | |
| AtomicBoolean done = new AtomicBoolean(); | |
| Runnable task = () -> { | |
| try { | |
| LOCAL.set(new Object()); | |
| } catch (UnsupportedOperationException expected) { | |
| done.set(true); | |
| } | |
| }; | |
| done.set(false); | |
| Thread thread1 = builder.unstarted(task); | |
| thread1.start(); | |
| thread1.join(); | |
| assertTrue(done.get()); | |
| done.set(false); | |
| Thread thread2 = builder.start(task); | |
| thread2.join(); | |
| assertTrue(done.get()); | |
| done.set(false); | |
| Thread thread3 = builder.factory().newThread(task); | |
| thread3.start(); | |
| thread3.join(); | |
| assertTrue(done.get()); | |
| } | |
| /** | |
| * Test Thread.Builder creates threads that allow thread locals. | |
| */ | |
| @Test | |
| void testThreadLocals1() throws Exception { | |
| Thread.Builder builder = Thread.ofPlatform(); | |
| testThreadLocals(builder); | |
| } | |
| @Test | |
| void testThreadLocals2() throws Exception { | |
| Thread.Builder builder = Thread.ofVirtual(); | |
| testThreadLocals(builder); | |
| } | |
| /** | |
| * Tests that a builder creates threads that inherits the initial values of | |
| * inheritable thread locals. | |
| */ | |
| private void testInheritedThreadLocals(Thread.Builder builder) throws Exception { | |
| Object value = new Object(); | |
| INHERITED_LOCAL.set(value); | |
| AtomicBoolean done = new AtomicBoolean(); | |
| Runnable task = () -> { | |
| assertTrue(INHERITED_LOCAL.get() == value); | |
| done.set(true); | |
| }; | |
| done.set(false); | |
| Thread thread1 = builder.unstarted(task); | |
| thread1.start(); | |
| thread1.join(); | |
| assertTrue(done.get()); | |
| done.set(false); | |
| Thread thread2 = builder.start(task); | |
| thread2.join(); | |
| assertTrue(done.get()); | |
| done.set(false); | |
| Thread thread3 = builder.factory().newThread(task); | |
| thread3.start(); | |
| thread3.join(); | |
| assertTrue(done.get()); | |
| } | |
| /** | |
| * Tests that a builder creates threads that do not inherit the initial values | |
| * of inheritable thread locals. | |
| */ | |
| private void testNoInheritedThreadLocals(Thread.Builder builder) throws Exception { | |
| Object value = new Object(); | |
| INHERITED_LOCAL.set(value); | |
| AtomicBoolean done = new AtomicBoolean(); | |
| Runnable task = () -> { | |
| assertNull(INHERITED_LOCAL.get()); | |
| done.set(true); | |
| }; | |
| done.set(false); | |
| Thread thread1 = builder.unstarted(task); | |
| thread1.start(); | |
| thread1.join(); | |
| assertTrue(done.get()); | |
| done.set(false); | |
| Thread thread2 = builder.start(task); | |
| thread2.join(); | |
| assertTrue(done.get()); | |
| done.set(false); | |
| Thread thread3 = builder.factory().newThread(task); | |
| thread3.start(); | |
| thread3.join(); | |
| assertTrue(done.get()); | |
| } | |
| /** | |
| * Test Thread.Builder creating threads that inherit or do not inherit | |
| * the initial values of inheritable thread locals. | |
| */ | |
| @Test | |
| void testInheritedThreadLocals1() throws Exception { | |
| Thread.Builder builder = Thread.ofPlatform(); | |
| testInheritedThreadLocals(builder); // default | |
| // do no inherit | |
| builder.inheritInheritableThreadLocals(false); | |
| testNoInheritedThreadLocals(builder); | |
| // inherit | |
| builder.inheritInheritableThreadLocals(true); | |
| testInheritedThreadLocals(builder); | |
| } | |
| @Test | |
| void testInheritedThreadLocals2() throws Exception { | |
| Thread.Builder builder = Thread.ofVirtual(); | |
| testInheritedThreadLocals(builder); // default | |
| // do no inherit | |
| builder.inheritInheritableThreadLocals(false); | |
| testNoInheritedThreadLocals(builder); | |
| // inherit | |
| builder.inheritInheritableThreadLocals(true); | |
| testInheritedThreadLocals(builder); | |
| } | |
| /** | |
| * Tests a builder creates threads that inherit the context class loader. | |
| */ | |
| private void testInheritContextClassLoader(Thread.Builder builder) throws Exception { | |
| ClassLoader savedCCL = Thread.currentThread().getContextClassLoader(); | |
| try { | |
| ClassLoader loader = new ClassLoader() { }; | |
| Thread.currentThread().setContextClassLoader(loader); | |
| var ref = new AtomicReference<ClassLoader>(); | |
| Runnable task = () -> { | |
| ref.set(Thread.currentThread().getContextClassLoader()); | |
| }; | |
| // unstarted | |
| Thread thread1 = builder.unstarted(task); | |
| assertTrue(thread1.getContextClassLoader() == loader); | |
| // started | |
| ref.set(null); | |
| thread1.start(); | |
| thread1.join(); | |
| assertTrue(ref.get() == loader); | |
| // factory | |
| Thread thread2 = builder.factory().newThread(task); | |
| assertTrue(thread2.getContextClassLoader() == loader); | |
| // started | |
| ref.set(null); | |
| thread2.start(); | |
| thread2.join(); | |
| assertTrue(ref.get() == loader); | |
| } finally { | |
| Thread.currentThread().setContextClassLoader(savedCCL); | |
| } | |
| } | |
| /** | |
| * Tests a builder creates threads does not inherit the context class loader. | |
| */ | |
| private void testNoInheritContextClassLoader(Thread.Builder builder) throws Exception { | |
| ClassLoader savedCCL = Thread.currentThread().getContextClassLoader(); | |
| try { | |
| Thread.currentThread().setContextClassLoader( new ClassLoader() { }); | |
| ClassLoader scl = ClassLoader.getSystemClassLoader(); | |
| var ref = new AtomicReference<ClassLoader>(); | |
| Runnable task = () -> { | |
| ref.set(Thread.currentThread().getContextClassLoader()); | |
| }; | |
| // unstarted | |
| Thread thread1 = builder.unstarted(task); | |
| assertTrue(thread1.getContextClassLoader() == scl); | |
| // started | |
| ref.set(null); | |
| thread1.start(); | |
| thread1.join(); | |
| assertTrue(ref.get() == scl); | |
| // factory | |
| Thread thread2 = builder.factory().newThread(task); | |
| assertTrue(thread2.getContextClassLoader() == scl); | |
| // started | |
| ref.set(null); | |
| thread2.start(); | |
| thread2.join(); | |
| assertTrue(ref.get() == scl); | |
| } finally { | |
| Thread.currentThread().setContextClassLoader(savedCCL); | |
| } | |
| } | |
| /** | |
| * Test Thread.Builder creating threads that inherit or do not inherit | |
| * the thread context class loader. | |
| */ | |
| @Test | |
| void testContextClassLoader1() throws Exception { | |
| Thread.Builder builder = Thread.ofPlatform(); | |
| testInheritContextClassLoader(builder); // default | |
| // do no inherit | |
| builder.inheritInheritableThreadLocals(false); | |
| testNoInheritContextClassLoader(builder); | |
| // inherit | |
| builder.inheritInheritableThreadLocals(true); | |
| testInheritContextClassLoader(builder); | |
| } | |
| @Test | |
| void testContextClassLoader2() throws Exception { | |
| Thread.Builder builder = Thread.ofVirtual(); | |
| testInheritContextClassLoader(builder); // default | |
| // do no inherit | |
| builder.inheritInheritableThreadLocals(false); | |
| testNoInheritContextClassLoader(builder); | |
| // inherit | |
| builder.inheritInheritableThreadLocals(true); | |
| testInheritContextClassLoader(builder); | |
| } | |
| /** | |
| * Test NullPointerException. | |
| */ | |
| @Test | |
| void testNulls1() { | |
| Thread.Builder.OfPlatform builder = Thread.ofPlatform(); | |
| assertThrows(NullPointerException.class, () -> builder.group(null)); | |
| assertThrows(NullPointerException.class, () -> builder.name(null)); | |
| assertThrows(NullPointerException.class, () -> builder.name(null, 0)); | |
| assertThrows(NullPointerException.class, () -> builder.uncaughtExceptionHandler(null)); | |
| assertThrows(NullPointerException.class, () -> builder.unstarted(null)); | |
| assertThrows(NullPointerException.class, () -> builder.start(null)); | |
| } | |
| @Test | |
| void testNulls2() { | |
| Thread.Builder builder = Thread.ofVirtual(); | |
| assertThrows(NullPointerException.class, () -> builder.name(null)); | |
| assertThrows(NullPointerException.class, () -> builder.name(null, 0)); | |
| assertThrows(NullPointerException.class, () -> builder.uncaughtExceptionHandler(null)); | |
| assertThrows(NullPointerException.class, () -> builder.unstarted(null)); | |
| assertThrows(NullPointerException.class, () -> builder.start(null)); | |
| } | |
| } |