undefect. CWE-407 — 63 sites patched across 27 ecosystems
Authors: russell@unturf.com · brackishbert@gmail.com · foxhop.net · TimeHexOn.com Patches, unit tests, benchmarks, whitepaper, and outreach briefs. Public domain — no copyright claimed. Use freely.
This commit is contained in:
commit
0a580b313d
70422 changed files with 17213626 additions and 0 deletions
805
test/jdk/java/lang/Thread/BuilderTest.java
Normal file
805
test/jdk/java/lang/Thread/BuilderTest.java
Normal file
|
|
@ -0,0 +1,805 @@
|
|||
/*
|
||||
* 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));
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue