Andrew Haley 221e1a4260 8286666: JEP 429: Implementation of Scoped Values (Incubator)
Reviewed-by: psandoz, dlong, alanb, mcimadamore
2022-12-07 10:14:06 +00:00

3068 lines
120 KiB
Java

/*
* Copyright (c) 1994, 2022, 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. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* 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.
*/
package java.lang;
import java.lang.ref.Reference;
import java.lang.reflect.Field;
import java.security.AccessController;
import java.security.AccessControlContext;
import java.security.Permission;
import java.security.PrivilegedAction;
import java.security.ProtectionDomain;
import java.time.Duration;
import java.util.Map;
import java.util.HashMap;
import java.util.Objects;
import java.util.concurrent.ThreadFactory;
import java.util.concurrent.locks.LockSupport;
import java.util.function.Predicate;
import java.util.stream.Stream;
import jdk.internal.event.ThreadSleepEvent;
import jdk.internal.javac.PreviewFeature;
import jdk.internal.misc.PreviewFeatures;
import jdk.internal.misc.StructureViolationExceptions;
import jdk.internal.misc.TerminatingThreadLocal;
import jdk.internal.misc.Unsafe;
import jdk.internal.misc.VM;
import jdk.internal.reflect.CallerSensitive;
import jdk.internal.reflect.Reflection;
import jdk.internal.vm.Continuation;
import jdk.internal.vm.ScopedValueContainer;
import jdk.internal.vm.StackableScope;
import jdk.internal.vm.ThreadContainer;
import jdk.internal.vm.annotation.ForceInline;
import jdk.internal.vm.annotation.Hidden;
import jdk.internal.vm.annotation.IntrinsicCandidate;
import sun.nio.ch.Interruptible;
import sun.security.util.SecurityConstants;
import static java.util.concurrent.TimeUnit.MILLISECONDS;
import static java.util.concurrent.TimeUnit.NANOSECONDS;
/**
* A <i>thread</i> is a thread of execution in a program. The Java
* virtual machine allows an application to have multiple threads of
* execution running concurrently.
*
* <p> {@code Thread} defines constructors and a {@link Builder} to create threads.
* {@linkplain #start() Starting} a thread schedules it to execute its {@link #run() run}
* method. The newly started thread executes concurrently with the thread that caused
* it to start.
*
* <p> A thread <i>terminates</i> if either its {@code run} method completes normally,
* or if its {@code run} method completes abruptly and the appropriate {@linkplain
* Thread.UncaughtExceptionHandler uncaught exception handler} completes normally or
* abruptly. With no code left to run, the thread has completed execution. The
* {@link #join() join} method can be used to wait for a thread to terminate.
*
* <p> Threads have a unique {@linkplain #threadId() identifier} and a {@linkplain
* #getName() name}. The identifier is generated when a {@code Thread} is created
* and cannot be changed. The thread name can be specified when creating a thread
* or can be {@linkplain #setName(String) changed} at a later time.
*
* <p> Threads support {@link ThreadLocal} variables. These are variables that are
* local to a thread, meaning a thread can have a copy of a variable that is set to
* a value that is independent of the value set by other threads. Thread also supports
* {@link InheritableThreadLocal} variables that are thread local variables that are
* inherited at Thread creation time from the parent Thread. Thread supports a special
* inheritable thread local for the thread {@linkplain #getContextClassLoader()
* context-class-loader}.
*
* <h2><a id="platform-threads">Platform threads</a></h2>
* <p> {@code Thread} supports the creation of <i>platform threads</i> that are
* typically mapped 1:1 to kernel threads scheduled by the operating system.
* Platform threads will usually have a large stack and other resources that are
* maintained by the operating system. Platforms threads are suitable for executing
* all types of tasks but may be a limited resource.
*
* <p> Platform threads get an automatically generated thread name by default.
*
* <p> Platform threads are designated <i>daemon</i> or <i>non-daemon</i> threads.
* When the Java virtual machine starts up, there is usually one non-daemon
* thread (the thread that typically calls the application's {@code main} method).
* The <a href="Runtime.html#shutdown">shutdown sequence</a> begins when all started
* non-daemon threads have terminated. Unstarted non-daemon threads do not prevent
* the shutdown sequence from beginning.
*
* <p> In addition to the daemon status, platform threads have a {@linkplain
* #getPriority() thread priority} and are members of a {@linkplain ThreadGroup
* thread group}.
*
* <h2><a id="virtual-threads">Virtual threads</a></h2>
* <p> {@code Thread} also supports the creation of <i>virtual threads</i>.
* Virtual threads are typically <i>user-mode threads</i> scheduled by the Java
* runtime rather than the operating system. Virtual threads will typically require
* few resources and a single Java virtual machine may support millions of virtual
* threads. Virtual threads are suitable for executing tasks that spend most of
* the time blocked, often waiting for I/O operations to complete. Virtual threads
* are not intended for long running CPU intensive operations.
*
* <p> Virtual threads typically employ a small set of platform threads used as
* <em>carrier threads</em>. Locking and I/O operations are examples of operations
* where a carrier thread may be re-scheduled from one virtual thread to another.
* Code executing in a virtual thread is not aware of the underlying carrier thread.
* The {@linkplain Thread#currentThread()} method, used to obtain a reference
* to the <i>current thread</i>, will always return the {@code Thread} object
* for the virtual thread.
*
* <p> Virtual threads do not have a thread name by default. The {@link #getName()
* getName} method returns the empty string if a thread name is not set.
*
* <p> Virtual threads are daemon threads and so do not prevent the
* <a href="Runtime.html#shutdown">shutdown sequence</a> from beginning.
* Virtual threads have a fixed {@linkplain #getPriority() thread priority}
* that cannot be changed.
*
* <h2>Creating and starting threads</h2>
*
* <p> {@code Thread} defines public constructors for creating platform threads and
* the {@link #start() start} method to schedule threads to execute. {@code Thread}
* may be extended for customization and other advanced reasons although most
* applications should have little need to do this.
*
* <p> {@code Thread} defines a {@link Builder} API for creating and starting both
* platform and virtual threads. The following are examples that use the builder:
* {@snippet :
* Runnable runnable = ...
*
* // Start a daemon thread to run a task
* Thread thread = Thread.ofPlatform().daemon().start(runnable);
*
* // Create an unstarted thread with name "duke", its start() method
* // must be invoked to schedule it to execute.
* Thread thread = Thread.ofPlatform().name("duke").unstarted(runnable);
*
* // A ThreadFactory that creates daemon threads named "worker-0", "worker-1", ...
* ThreadFactory factory = Thread.ofPlatform().daemon().name("worker-", 0).factory();
*
* // Start a virtual thread to run a task
* Thread thread = Thread.ofVirtual().start(runnable);
*
* // A ThreadFactory that creates virtual threads
* ThreadFactory factory = Thread.ofVirtual().factory();
* }
*
* <h2><a id="inheritance">Inheritance when creating threads</a></h2>
* A {@code Thread} inherits its initial values of {@linkplain InheritableThreadLocal
* inheritable-thread-local} variables (including the context class loader) from
* the parent thread values at the time that the child {@code Thread} is created.
* The 5-param {@linkplain Thread#Thread(ThreadGroup, Runnable, String, long, boolean)
* constructor} can be used to create a thread that does not inherit its initial
* values from the constructing thread. When using a {@code Thread.Builder}, the
* {@link Builder#inheritInheritableThreadLocals(boolean) inheritInheritableThreadLocals}
* method can be used to select if the initial values are inherited.
*
* <p> Platform threads inherit the daemon status, thread priority, and when not
* provided (or not selected by a security manager), the thread group.
*
* <p> Creating a platform thread {@linkplain AccessController#getContext() captures} the
* {@linkplain AccessControlContext caller context} to limit the {@linkplain Permission
* permissions} of the new thread when it executes code that performs a {@linkplain
* AccessController#doPrivileged(PrivilegedAction) privileged action}. The captured
* caller context is the new thread's "Inherited {@link AccessControlContext}". Creating
* a virtual thread does not capture the caller context; virtual threads have no
* permissions when executing code that performs a privileged action.
*
* <p> Unless otherwise specified, passing a {@code null} argument to a constructor
* or method in this class will cause a {@link NullPointerException} to be thrown.
*
* @implNote
* In the JDK Reference Implementation, the virtual thread scheduler may be configured
* with the following system properties:
* <table class="striped">
* <caption style="display:none:">System properties</caption>
* <thead>
* <tr>
* <th scope="col">System property</th>
* <th scope="col">Description</th>
* </tr>
* </thead>
* <tbody>
* <tr>
* <th scope="row">
* {@systemProperty jdk.virtualThreadScheduler.parallelism}
* </th>
* <td> The number of platform threads available for scheduling virtual
* threads. It defaults to the number of available processors. </td>
* </tr>
* <tr>
* <th scope="row">
* {@systemProperty jdk.virtualThreadScheduler.maxPoolSize}
* </th>
* <td> The maximum number of platform threads available to the scheduler.
* It defaults to 256. </td>
* </tr>
* </tbody>
* </table>
*
* @since 1.0
*/
public class Thread implements Runnable {
/* Make sure registerNatives is the first thing <clinit> does. */
private static native void registerNatives();
static {
registerNatives();
}
/* Reserved for exclusive use by the JVM, maybe move to FieldHolder */
private long eetop;
// thread id
private final long tid;
// thread name
private volatile String name;
// interrupt status (read/written by VM)
volatile boolean interrupted;
// context ClassLoader
private volatile ClassLoader contextClassLoader;
// inherited AccessControlContext, this could be moved to FieldHolder
@SuppressWarnings("removal")
private AccessControlContext inheritedAccessControlContext;
// Additional fields for platform threads.
// All fields, except task, are accessed directly by the VM.
private static class FieldHolder {
final ThreadGroup group;
final Runnable task;
final long stackSize;
volatile int priority;
volatile boolean daemon;
volatile int threadStatus;
FieldHolder(ThreadGroup group,
Runnable task,
long stackSize,
int priority,
boolean daemon) {
this.group = group;
this.task = task;
this.stackSize = stackSize;
this.priority = priority;
if (daemon)
this.daemon = true;
}
}
private final FieldHolder holder;
/*
* ThreadLocal values pertaining to this thread. This map is maintained
* by the ThreadLocal class. */
ThreadLocal.ThreadLocalMap threadLocals;
/*
* InheritableThreadLocal values pertaining to this thread. This map is
* maintained by the InheritableThreadLocal class.
*/
ThreadLocal.ThreadLocalMap inheritableThreadLocals;
/*
* Scoped value bindings are maintained by the ScopedValue class.
*/
private Object scopedValueBindings;
// Special value to indicate this is a newly-created Thread
// Note that his must match the declaration in ScopedValue.
private static final Object NEW_THREAD_BINDINGS = Thread.class;
static Object scopedValueBindings() {
return currentThread().scopedValueBindings;
}
static void setScopedValueBindings(Object bindings) {
currentThread().scopedValueBindings = bindings;
}
/**
* Search the stack for the most recent scoped-value bindings.
*/
@IntrinsicCandidate
static native Object findScopedValueBindings();
/**
* Inherit the scoped-value bindings from the given container.
* Invoked when starting a thread.
*/
void inheritScopedValueBindings(ThreadContainer container) {
ScopedValueContainer.BindingsSnapshot snapshot;
if (container.owner() != null
&& (snapshot = container.scopedValueBindings()) != null) {
// bindings established for running/calling an operation
Object bindings = snapshot.scopedValueBindings();
if (currentThread().scopedValueBindings != bindings) {
StructureViolationExceptions.throwException("Scoped value bindings have changed");
}
this.scopedValueBindings = bindings;
}
}
/*
* Lock object for thread interrupt.
*/
final Object interruptLock = new Object();
/**
* The argument supplied to the current call to
* java.util.concurrent.locks.LockSupport.park.
* Set by (private) java.util.concurrent.locks.LockSupport.setBlocker
* Accessed using java.util.concurrent.locks.LockSupport.getBlocker
*/
private volatile Object parkBlocker;
/* The object in which this thread is blocked in an interruptible I/O
* operation, if any. The blocker's interrupt method should be invoked
* after setting this thread's interrupt status.
*/
volatile Interruptible nioBlocker;
/* Set the blocker field; invoked via jdk.internal.access.SharedSecrets
* from java.nio code
*/
static void blockedOn(Interruptible b) {
Thread me = Thread.currentThread();
synchronized (me.interruptLock) {
me.nioBlocker = b;
}
}
/**
* The minimum priority that a thread can have.
*/
public static final int MIN_PRIORITY = 1;
/**
* The default priority that is assigned to a thread.
*/
public static final int NORM_PRIORITY = 5;
/**
* The maximum priority that a thread can have.
*/
public static final int MAX_PRIORITY = 10;
/*
* Current inner-most continuation.
*/
private Continuation cont;
/**
* Returns the current continuation.
*/
Continuation getContinuation() {
return cont;
}
/**
* Sets the current continuation.
*/
void setContinuation(Continuation cont) {
this.cont = cont;
}
/**
* Returns the Thread object for the current platform thread. If the
* current thread is a virtual thread then this method returns the carrier.
*/
@IntrinsicCandidate
static native Thread currentCarrierThread();
/**
* Returns the Thread object for the current thread.
* @return the current thread
*/
@IntrinsicCandidate
public static native Thread currentThread();
/**
* Sets the Thread object to be returned by Thread.currentThread().
*/
@IntrinsicCandidate
native void setCurrentThread(Thread thread);
// ScopedValue support:
@IntrinsicCandidate
static native Object[] scopedValueCache();
@IntrinsicCandidate
static native void setScopedValueCache(Object[] cache);
@IntrinsicCandidate
static native void ensureMaterializedForStackWalk(Object o);
/**
* A hint to the scheduler that the current thread is willing to yield
* its current use of a processor. The scheduler is free to ignore this
* hint.
*
* <p> Yield is a heuristic attempt to improve relative progression
* between threads that would otherwise over-utilise a CPU. Its use
* should be combined with detailed profiling and benchmarking to
* ensure that it actually has the desired effect.
*
* <p> It is rarely appropriate to use this method. It may be useful
* for debugging or testing purposes, where it may help to reproduce
* bugs due to race conditions. It may also be useful when designing
* concurrency control constructs such as the ones in the
* {@link java.util.concurrent.locks} package.
*/
public static void yield() {
if (currentThread() instanceof VirtualThread vthread) {
vthread.tryYield();
} else {
yield0();
}
}
private static native void yield0();
/**
* Causes the currently executing thread to sleep (temporarily cease
* execution) for the specified number of milliseconds, subject to
* the precision and accuracy of system timers and schedulers. The thread
* does not lose ownership of any monitors.
*
* @param millis
* the length of time to sleep in milliseconds
*
* @throws IllegalArgumentException
* if the value of {@code millis} is negative
*
* @throws InterruptedException
* if any thread has interrupted the current thread. The
* <i>interrupted status</i> of the current thread is
* cleared when this exception is thrown.
*/
public static void sleep(long millis) throws InterruptedException {
if (millis < 0) {
throw new IllegalArgumentException("timeout value is negative");
}
if (currentThread() instanceof VirtualThread vthread) {
long nanos = MILLISECONDS.toNanos(millis);
vthread.sleepNanos(nanos);
return;
}
if (ThreadSleepEvent.isTurnedOn()) {
ThreadSleepEvent event = new ThreadSleepEvent();
try {
event.time = MILLISECONDS.toNanos(millis);
event.begin();
sleep0(millis);
} finally {
event.commit();
}
} else {
sleep0(millis);
}
}
private static native void sleep0(long millis) throws InterruptedException;
/**
* Causes the currently executing thread to sleep (temporarily cease
* execution) for the specified number of milliseconds plus the specified
* number of nanoseconds, subject to the precision and accuracy of system
* timers and schedulers. The thread does not lose ownership of any
* monitors.
*
* @param millis
* the length of time to sleep in milliseconds
*
* @param nanos
* {@code 0-999999} additional nanoseconds to sleep
*
* @throws IllegalArgumentException
* if the value of {@code millis} is negative, or the value of
* {@code nanos} is not in the range {@code 0-999999}
*
* @throws InterruptedException
* if any thread has interrupted the current thread. The
* <i>interrupted status</i> of the current thread is
* cleared when this exception is thrown.
*/
public static void sleep(long millis, int nanos) throws InterruptedException {
if (millis < 0) {
throw new IllegalArgumentException("timeout value is negative");
}
if (nanos < 0 || nanos > 999999) {
throw new IllegalArgumentException("nanosecond timeout value out of range");
}
if (currentThread() instanceof VirtualThread vthread) {
// total sleep time, in nanoseconds
long totalNanos = MILLISECONDS.toNanos(millis);
totalNanos += Math.min(Long.MAX_VALUE - totalNanos, nanos);
vthread.sleepNanos(totalNanos);
return;
}
if (nanos > 0 && millis < Long.MAX_VALUE) {
millis++;
}
sleep(millis);
}
/**
* Causes the currently executing thread to sleep (temporarily cease
* execution) for the specified duration, subject to the precision and
* accuracy of system timers and schedulers. This method is a no-op if
* the duration is {@linkplain Duration#isNegative() negative}.
*
* @param duration
* the duration to sleep
*
* @throws InterruptedException
* if the current thread is interrupted while sleeping. The
* <i>interrupted status</i> of the current thread is
* cleared when this exception is thrown.
*
* @since 19
*/
public static void sleep(Duration duration) throws InterruptedException {
long nanos = NANOSECONDS.convert(duration); // MAX_VALUE if > 292 years
if (nanos < 0)
return;
if (currentThread() instanceof VirtualThread vthread) {
vthread.sleepNanos(nanos);
return;
}
// convert to milliseconds
long millis = MILLISECONDS.convert(nanos, NANOSECONDS);
if (nanos > NANOSECONDS.convert(millis, MILLISECONDS)) {
millis += 1L;
}
sleep(millis);
}
/**
* Indicates that the caller is momentarily unable to progress, until the
* occurrence of one or more actions on the part of other activities. By
* invoking this method within each iteration of a spin-wait loop construct,
* the calling thread indicates to the runtime that it is busy-waiting.
* The runtime may take action to improve the performance of invoking
* spin-wait loop constructions.
*
* @apiNote
* As an example consider a method in a class that spins in a loop until
* some flag is set outside of that method. A call to the {@code onSpinWait}
* method should be placed inside the spin loop.
* {@snippet :
* class EventHandler {
* volatile boolean eventNotificationNotReceived;
* void waitForEventAndHandleIt() {
* while ( eventNotificationNotReceived ) {
* Thread.onSpinWait();
* }
* readAndProcessEvent();
* }
*
* void readAndProcessEvent() {
* // Read event from some source and process it
* . . .
* }
* }
* }
* <p>
* The code above would remain correct even if the {@code onSpinWait}
* method was not called at all. However on some architectures the Java
* Virtual Machine may issue the processor instructions to address such
* code patterns in a more beneficial way.
*
* @since 9
*/
@IntrinsicCandidate
public static void onSpinWait() {}
/**
* Characteristic value signifying that the thread cannot set values for its
* copy of {@link ThreadLocal thread-locals}.
* See Thread initialization.
*/
static final int NO_THREAD_LOCALS = 1 << 1;
/**
* Characteristic value signifying that initial values for {@link
* InheritableThreadLocal inheritable-thread-locals} are not inherited from
* the constructing thread.
* See Thread initialization.
*/
static final int NO_INHERIT_THREAD_LOCALS = 1 << 2;
/**
* Helper class to generate thread identifiers. The identifiers start at
* 2 as this class cannot be used during early startup to generate the
* identifier for the primordial thread. The counter is off-heap and
* shared with the VM to allow it assign thread identifiers to non-Java
* threads.
* See Thread initialization.
*/
private static class ThreadIdentifiers {
private static final Unsafe U;
private static final long NEXT_TID_OFFSET;
static {
U = Unsafe.getUnsafe();
NEXT_TID_OFFSET = Thread.getNextThreadIdOffset();
}
static long next() {
return U.getAndAddLong(null, NEXT_TID_OFFSET, 1);
}
}
/**
* Returns the context class loader to inherit from the parent thread.
* See Thread initialization.
*/
private static ClassLoader contextClassLoader(Thread parent) {
@SuppressWarnings("removal")
SecurityManager sm = System.getSecurityManager();
if (sm == null || isCCLOverridden(parent.getClass())) {
return parent.getContextClassLoader();
} else {
// skip call to getContextClassLoader
ClassLoader cl = parent.contextClassLoader;
return (isSupportedClassLoader(cl)) ? cl : ClassLoader.getSystemClassLoader();
}
}
/**
* Initializes a platform Thread.
*
* @param g the Thread group, can be null
* @param name the name of the new Thread
* @param characteristics thread characteristics
* @param task the object whose run() method gets called
* @param stackSize the desired stack size for the new thread, or
* zero to indicate that this parameter is to be ignored.
* @param acc the AccessControlContext to inherit, or
* AccessController.getContext() if null
*/
@SuppressWarnings("removal")
Thread(ThreadGroup g, String name, int characteristics, Runnable task,
long stackSize, AccessControlContext acc) {
Thread parent = currentThread();
boolean attached = (parent == this); // primordial or JNI attached
if (attached) {
if (g == null) {
throw new InternalError("group cannot be null when attaching");
}
this.holder = new FieldHolder(g, task, stackSize, NORM_PRIORITY, false);
} else {
SecurityManager sm = System.getSecurityManager();
if (g == null) {
// the security manager can choose the thread group
if (sm != null) {
g = sm.getThreadGroup();
}
// default to current thread's group
if (g == null) {
g = parent.getThreadGroup();
}
}
// permission checks when creating a child Thread
if (sm != null) {
sm.checkAccess(g);
if (isCCLOverridden(getClass())) {
sm.checkPermission(SecurityConstants.SUBCLASS_IMPLEMENTATION_PERMISSION);
}
}
int priority = Math.min(parent.getPriority(), g.getMaxPriority());
this.holder = new FieldHolder(g, task, stackSize, priority, parent.isDaemon());
}
if (attached && VM.initLevel() < 1) {
this.tid = 1; // primordial thread
} else {
this.tid = ThreadIdentifiers.next();
}
this.name = (name != null) ? name : genThreadName();
if (acc != null) {
this.inheritedAccessControlContext = acc;
} else {
this.inheritedAccessControlContext = AccessController.getContext();
}
// thread locals
if (!attached) {
if ((characteristics & NO_THREAD_LOCALS) != 0) {
this.threadLocals = ThreadLocal.ThreadLocalMap.NOT_SUPPORTED;
this.inheritableThreadLocals = ThreadLocal.ThreadLocalMap.NOT_SUPPORTED;
this.contextClassLoader = Constants.NOT_SUPPORTED_CLASSLOADER;
} else if ((characteristics & NO_INHERIT_THREAD_LOCALS) == 0) {
ThreadLocal.ThreadLocalMap parentMap = parent.inheritableThreadLocals;
if (parentMap != null
&& parentMap != ThreadLocal.ThreadLocalMap.NOT_SUPPORTED
&& parentMap.size() > 0) {
this.inheritableThreadLocals = ThreadLocal.createInheritedMap(parentMap);
}
ClassLoader parentLoader = contextClassLoader(parent);
if (VM.isBooted() && !isSupportedClassLoader(parentLoader)) {
// parent does not support thread locals so no CCL to inherit
this.contextClassLoader = ClassLoader.getSystemClassLoader();
} else {
this.contextClassLoader = parentLoader;
}
} else if (VM.isBooted()) {
// default CCL to the system class loader when not inheriting
this.contextClassLoader = ClassLoader.getSystemClassLoader();
}
}
// Special value to indicate this is a newly-created Thread
// Note that his must match the declaration in ScopedValue.
this.scopedValueBindings = NEW_THREAD_BINDINGS;
}
/**
* Initializes a virtual Thread.
*
* @param name thread name, can be null
* @param characteristics thread characteristics
* @param bound true when bound to an OS thread
*/
Thread(String name, int characteristics, boolean bound) {
this.tid = ThreadIdentifiers.next();
this.name = (name != null) ? name : "";
this.inheritedAccessControlContext = Constants.NO_PERMISSIONS_ACC;
// thread locals
if ((characteristics & NO_THREAD_LOCALS) != 0) {
this.threadLocals = ThreadLocal.ThreadLocalMap.NOT_SUPPORTED;
this.inheritableThreadLocals = ThreadLocal.ThreadLocalMap.NOT_SUPPORTED;
this.contextClassLoader = Constants.NOT_SUPPORTED_CLASSLOADER;
} else if ((characteristics & NO_INHERIT_THREAD_LOCALS) == 0) {
Thread parent = currentThread();
ThreadLocal.ThreadLocalMap parentMap = parent.inheritableThreadLocals;
if (parentMap != null
&& parentMap != ThreadLocal.ThreadLocalMap.NOT_SUPPORTED
&& parentMap.size() > 0) {
this.inheritableThreadLocals = ThreadLocal.createInheritedMap(parentMap);
}
ClassLoader parentLoader = contextClassLoader(parent);
if (isSupportedClassLoader(parentLoader)) {
this.contextClassLoader = parentLoader;
} else {
// parent does not support thread locals so no CCL to inherit
this.contextClassLoader = ClassLoader.getSystemClassLoader();
}
} else {
// default CCL to the system class loader when not inheriting
this.contextClassLoader = ClassLoader.getSystemClassLoader();
}
// Special value to indicate this is a newly-created Thread
this.scopedValueBindings = NEW_THREAD_BINDINGS;
// create a FieldHolder object, needed when bound to an OS thread
if (bound) {
ThreadGroup g = Constants.VTHREAD_GROUP;
int pri = NORM_PRIORITY;
this.holder = new FieldHolder(g, null, -1, pri, true);
} else {
this.holder = null;
}
}
/**
* Returns a builder for creating a platform {@code Thread} or {@code ThreadFactory}
* that creates platform threads.
*
* <p> <a id="ofplatform-security"><b>Interaction with security manager when
* creating platform threads</b></a>
* <p> Creating a platform thread when there is a security manager set will
* invoke the security manager's {@link SecurityManager#checkAccess(ThreadGroup)
* checkAccess(ThreadGroup)} method with the thread's thread group.
* If the thread group has not been set with the {@link
* Builder.OfPlatform#group(ThreadGroup) OfPlatform.group} method then the
* security manager's {@link SecurityManager#getThreadGroup() getThreadGroup}
* method will be invoked first to select the thread group. If the security
* manager {@code getThreadGroup} method returns {@code null} then the thread
* group of the constructing thread is used.
*
* @apiNote The following are examples using the builder:
* {@snippet :
* // Start a daemon thread to run a task
* Thread thread = Thread.ofPlatform().daemon().start(runnable);
*
* // Create an unstarted thread with name "duke", its start() method
* // must be invoked to schedule it to execute.
* Thread thread = Thread.ofPlatform().name("duke").unstarted(runnable);
*
* // A ThreadFactory that creates daemon threads named "worker-0", "worker-1", ...
* ThreadFactory factory = Thread.ofPlatform().daemon().name("worker-", 0).factory();
* }
*
* @return A builder for creating {@code Thread} or {@code ThreadFactory} objects.
* @since 19
*/
@PreviewFeature(feature = PreviewFeature.Feature.VIRTUAL_THREADS)
public static Builder.OfPlatform ofPlatform() {
return new ThreadBuilders.PlatformThreadBuilder();
}
/**
* Returns a builder for creating a virtual {@code Thread} or {@code ThreadFactory}
* that creates virtual threads.
*
* @apiNote The following are examples using the builder:
* {@snippet :
* // Start a virtual thread to run a task.
* Thread thread = Thread.ofVirtual().start(runnable);
*
* // A ThreadFactory that creates virtual threads
* ThreadFactory factory = Thread.ofVirtual().factory();
* }
*
* @return A builder for creating {@code Thread} or {@code ThreadFactory} objects.
* @throws UnsupportedOperationException if preview features are not enabled
* @since 19
*/
@PreviewFeature(feature = PreviewFeature.Feature.VIRTUAL_THREADS)
public static Builder.OfVirtual ofVirtual() {
PreviewFeatures.ensureEnabled();
return new ThreadBuilders.VirtualThreadBuilder();
}
/**
* A builder for {@link Thread} and {@link ThreadFactory} objects.
*
* <p> {@code Builder} defines methods to set {@code Thread} properties such
* as the thread {@link #name(String) name}. This includes properties that would
* otherwise be <a href="Thread.html#inheritance">inherited</a>. Once set, a
* {@code Thread} or {@code ThreadFactory} is created with the following methods:
*
* <ul>
* <li> The {@linkplain #unstarted(Runnable) unstarted} method creates a new
* <em>unstarted</em> {@code Thread} to run a task. The {@code Thread}'s
* {@link Thread#start() start} method must be invoked to schedule the
* thread to execute.
* <li> The {@linkplain #start(Runnable) start} method creates a new {@code
* Thread} to run a task and schedules the thread to execute.
* <li> The {@linkplain #factory() factory} method creates a {@code ThreadFactory}.
* </ul>
*
* <p> A {@code Thread.Builder} is not thread safe. The {@code ThreadFactory}
* returned by the builder's {@code factory()} method is thread safe.
*
* <p> Unless otherwise specified, passing a null argument to a method in
* this interface causes a {@code NullPointerException} to be thrown.
*
* @see Thread#ofPlatform()
* @see Thread#ofVirtual()
* @since 19
*/
@PreviewFeature(feature = PreviewFeature.Feature.VIRTUAL_THREADS)
public sealed interface Builder
permits Builder.OfPlatform,
Builder.OfVirtual,
ThreadBuilders.BaseThreadBuilder {
/**
* Sets the thread name.
* @param name thread name
* @return this builder
*/
Builder name(String name);
/**
* Sets the thread name to be the concatenation of a string prefix and
* the string representation of a counter value. The counter's initial
* value is {@code start}. It is incremented after a {@code Thread} is
* created with this builder so that the next thread is named with
* the new counter value. A {@code ThreadFactory} created with this
* builder is seeded with the current value of the counter. The {@code
* ThreadFactory} increments its copy of the counter after {@link
* ThreadFactory#newThread(Runnable) newThread} is used to create a
* {@code Thread}.
*
* @apiNote
* The following example creates a builder that is invoked twice to start
* two threads named "{@code worker-0}" and "{@code worker-1}".
* {@snippet :
* Thread.Builder builder = Thread.ofPlatform().name("worker-", 0);
* Thread t1 = builder.start(task1); // name "worker-0"
* Thread t2 = builder.start(task2); // name "worker-1"
* }
*
* @param prefix thread name prefix
* @param start the starting value of the counter
* @return this builder
* @throws IllegalArgumentException if start is negative
*/
Builder name(String prefix, long start);
/**
* Sets whether the thread is allowed to set values for its copy of {@linkplain
* ThreadLocal thread-local} variables. The default is to allow. If not allowed,
* then any attempt by the thread to set a value for a thread-local with the
* {@link ThreadLocal#set(Object)} method throws {@code
* UnsupportedOperationException}. Any attempt to set the thread's context
* class loader with {@link Thread#setContextClassLoader(ClassLoader)
* setContextClassLoader} also throws. The {@link ThreadLocal#get()} method
* always returns the {@linkplain ThreadLocal#initialValue() initial-value}
* when thread locals are not allowed.
*
* @apiNote This method is intended for cases where there are a large number of
* threads and where potentially unbounded memory usage due to thread locals is
* a concern. Disallowing a thread to set its copy of thread-local variables
* creates the potential for exceptions at run-time so great care is required
* when the thread is used to invoke arbitrary code.
*
* @param allow {@code true} to allow, {@code false} to disallow
* @return this builder
*/
Builder allowSetThreadLocals(boolean allow);
/**
* Sets whether the thread inherits the initial values of {@linkplain
* InheritableThreadLocal inheritable-thread-local} variables from the
* constructing thread. The default is to inherit.
*
* <p> The initial values of {@code InheritableThreadLocal}s are never inherited
* when {@link #allowSetThreadLocals(boolean)} is used to disallow the thread
* to have its own copy of thread-local variables.
*
* @param inherit {@code true} to inherit, {@code false} to not inherit
* @return this builder
*/
Builder inheritInheritableThreadLocals(boolean inherit);
/**
* Sets the uncaught exception handler.
* @param ueh uncaught exception handler
* @return this builder
*/
Builder uncaughtExceptionHandler(UncaughtExceptionHandler ueh);
/**
* Creates a new {@code Thread} from the current state of the builder to
* run the given task. The {@code Thread}'s {@link Thread#start() start}
* method must be invoked to schedule the thread to execute.
*
* @param task the object to run when the thread executes
* @return a new unstarted Thread
* @throws SecurityException if denied by the security manager
* (See <a href="Thread.html#ofplatform-security">Interaction with
* security manager when creating platform threads</a>)
*
* @see <a href="Thread.html#inheritance">Inheritance when creating threads</a>
*/
Thread unstarted(Runnable task);
/**
* Creates a new {@code Thread} from the current state of the builder and
* schedules it to execute.
*
* @param task the object to run when the thread executes
* @return a new started Thread
* @throws SecurityException if denied by the security manager
* (See <a href="Thread.html#ofplatform-security">Interaction with
* security manager when creating platform threads</a>)
*
* @see <a href="Thread.html#inheritance">Inheritance when creating threads</a>
*/
Thread start(Runnable task);
/**
* Returns a {@code ThreadFactory} to create threads from the current
* state of the builder. The returned thread factory is safe for use by
* multiple concurrent threads.
*
* @return a thread factory to create threads
*/
ThreadFactory factory();
/**
* A builder for creating a platform {@link Thread} or {@link ThreadFactory}
* that creates platform threads.
*
* <p> Unless otherwise specified, passing a null argument to a method in
* this interface causes a {@code NullPointerException} to be thrown.
*
* @see Thread#ofPlatform()
* @since 19
*/
@PreviewFeature(feature = PreviewFeature.Feature.VIRTUAL_THREADS)
sealed interface OfPlatform extends Builder
permits ThreadBuilders.PlatformThreadBuilder {
@Override OfPlatform name(String name);
/**
* @throws IllegalArgumentException {@inheritDoc}
*/
@Override OfPlatform name(String prefix, long start);
@Override OfPlatform allowSetThreadLocals(boolean allow);
@Override OfPlatform inheritInheritableThreadLocals(boolean inherit);
@Override OfPlatform uncaughtExceptionHandler(UncaughtExceptionHandler ueh);
/**
* Sets the thread group.
* @param group the thread group
* @return this builder
*/
OfPlatform group(ThreadGroup group);
/**
* Sets the daemon status.
* @param on {@code true} to create daemon threads
* @return this builder
*/
OfPlatform daemon(boolean on);
/**
* Sets the daemon status to {@code true}.
* @implSpec The default implementation invokes {@linkplain #daemon(boolean)} with
* a value of {@code true}.
* @return this builder
*/
default OfPlatform daemon() {
return daemon(true);
}
/**
* Sets the thread priority.
* @param priority priority
* @return this builder
* @throws IllegalArgumentException if the priority is less than
* {@link Thread#MIN_PRIORITY} or greater than {@link Thread#MAX_PRIORITY}
*/
OfPlatform priority(int priority);
/**
* Sets the desired stack size.
*
* <p> The stack size is the approximate number of bytes of address space
* that the Java virtual machine is to allocate for the thread's stack. The
* effect is highly platform dependent and the Java virtual machine is free
* to treat the {@code stackSize} parameter as a "suggestion". If the value
* is unreasonably low for the platform then a platform specific minimum
* may be used. If the value is unreasonably high then a platform specific
* maximum may be used. A value of zero is always ignored.
*
* @param stackSize the desired stack size
* @return this builder
* @throws IllegalArgumentException if the stack size is negative
*/
OfPlatform stackSize(long stackSize);
}
/**
* A builder for creating a virtual {@link Thread} or {@link ThreadFactory}
* that creates virtual threads.
*
* <p> Unless otherwise specified, passing a null argument to a method in
* this interface causes a {@code NullPointerException} to be thrown.
*
* @see Thread#ofVirtual()
* @since 19
*/
@PreviewFeature(feature = PreviewFeature.Feature.VIRTUAL_THREADS)
sealed interface OfVirtual extends Builder
permits ThreadBuilders.VirtualThreadBuilder {
@Override OfVirtual name(String name);
/**
* @throws IllegalArgumentException {@inheritDoc}
*/
@Override OfVirtual name(String prefix, long start);
@Override OfVirtual allowSetThreadLocals(boolean allow);
@Override OfVirtual inheritInheritableThreadLocals(boolean inherit);
@Override OfVirtual uncaughtExceptionHandler(UncaughtExceptionHandler ueh);
}
}
/**
* Throws CloneNotSupportedException as a Thread can not be meaningfully
* cloned. Construct a new Thread instead.
*
* @throws CloneNotSupportedException
* always
*/
@Override
protected Object clone() throws CloneNotSupportedException {
throw new CloneNotSupportedException();
}
/**
* Helper class for auto-numbering platform threads. The numbers start at
* 0 and are separate from the thread identifier for historical reasons.
*/
private static class ThreadNumbering {
private static final Unsafe U;
private static final Object NEXT_BASE;
private static final long NEXT_OFFSET;
static {
U = Unsafe.getUnsafe();
try {
Field nextField = ThreadNumbering.class.getDeclaredField("next");
NEXT_BASE = U.staticFieldBase(nextField);
NEXT_OFFSET = U.staticFieldOffset(nextField);
} catch (NoSuchFieldException e) {
throw new ExceptionInInitializerError(e);
}
}
private static volatile int next;
static int next() {
return U.getAndAddInt(NEXT_BASE, NEXT_OFFSET, 1);
}
}
/**
* Generates a thread name of the form {@code Thread-<n>}.
*/
static String genThreadName() {
return "Thread-" + ThreadNumbering.next();
}
/**
* Throws NullPointerException if the name is null. Avoids use of
* Objects.requireNonNull in early startup.
*/
private static String checkName(String name) {
if (name == null)
throw new NullPointerException("'name' is null");
return name;
}
/**
* Initializes a new platform {@code Thread}. This constructor has the same
* effect as {@linkplain #Thread(ThreadGroup,Runnable,String) Thread}
* {@code (null, null, gname)}, where {@code gname} is a newly generated
* name. Automatically generated names are of the form
* {@code "Thread-"+}<i>n</i>, where <i>n</i> is an integer.
*
* <p> This constructor is only useful when extending {@code Thread} to
* override the {@link #run()} method.
*
* @see <a href="#inheritance">Inheritance when creating threads</a>
*/
public Thread() {
this(null, null, 0, null, 0, null);
}
/**
* Initializes a new platform {@code Thread}. This constructor has the same
* effect as {@linkplain #Thread(ThreadGroup,Runnable,String) Thread}
* {@code (null, task, gname)}, where {@code gname} is a newly generated
* name. Automatically generated names are of the form
* {@code "Thread-"+}<i>n</i>, where <i>n</i> is an integer.
*
* <p> For a non-null task, invoking this constructor directly is equivalent to:
* <pre>{@code Thread.ofPlatform().unstarted(task); }</pre>
*
* @param task
* the object whose {@code run} method is invoked when this thread
* is started. If {@code null}, this classes {@code run} method does
* nothing.
*
* @see <a href="#inheritance">Inheritance when creating threads</a>
*/
public Thread(Runnable task) {
this(null, null, 0, task, 0, null);
}
/**
* Creates a new Thread that inherits the given AccessControlContext
* but thread-local variables are not inherited.
* This is not a public constructor.
*/
Thread(Runnable task, @SuppressWarnings("removal") AccessControlContext acc) {
this(null, null, 0, task, 0, acc);
}
/**
* Initializes a new platform {@code Thread}. This constructor has the same
* effect as {@linkplain #Thread(ThreadGroup,Runnable,String) Thread}
* {@code (group, task, gname)}, where {@code gname} is a newly generated
* name. Automatically generated names are of the form
* {@code "Thread-"+}<i>n</i>, where <i>n</i> is an integer.
*
* <p> For a non-null group and task, invoking this constructor directly is
* equivalent to:
* <pre>{@code Thread.ofPlatform().group(group).unstarted(task); }</pre>
*
* @param group
* the thread group. If {@code null} and there is a security
* manager, the group is determined by {@linkplain
* SecurityManager#getThreadGroup SecurityManager.getThreadGroup()}.
* If there is not a security manager or {@code
* SecurityManager.getThreadGroup()} returns {@code null}, the group
* is set to the current thread's thread group.
*
* @param task
* the object whose {@code run} method is invoked when this thread
* is started. If {@code null}, this thread's run method is invoked.
*
* @throws SecurityException
* if the current thread cannot create a thread in the specified
* thread group
*
* @see <a href="#inheritance">Inheritance when creating threads</a>
*/
public Thread(ThreadGroup group, Runnable task) {
this(group, null, 0, task, 0, null);
}
/**
* Initializes a new platform {@code Thread}. This constructor has the same
* effect as {@linkplain #Thread(ThreadGroup,Runnable,String) Thread}
* {@code (null, null, name)}.
*
* <p> This constructor is only useful when extending {@code Thread} to
* override the {@link #run()} method.
*
* @param name
* the name of the new thread
*
* @see <a href="#inheritance">Inheritance when creating threads</a>
*/
public Thread(String name) {
this(null, checkName(name), 0, null, 0, null);
}
/**
* Initializes a new platform {@code Thread}. This constructor has the same
* effect as {@linkplain #Thread(ThreadGroup,Runnable,String) Thread}
* {@code (group, null, name)}.
*
* <p> This constructor is only useful when extending {@code Thread} to
* override the {@link #run()} method.
*
* @param group
* the thread group. If {@code null} and there is a security
* manager, the group is determined by {@linkplain
* SecurityManager#getThreadGroup SecurityManager.getThreadGroup()}.
* If there is not a security manager or {@code
* SecurityManager.getThreadGroup()} returns {@code null}, the group
* is set to the current thread's thread group.
*
* @param name
* the name of the new thread
*
* @throws SecurityException
* if the current thread cannot create a thread in the specified
* thread group
*
* @see <a href="#inheritance">Inheritance when creating threads</a>
*/
public Thread(ThreadGroup group, String name) {
this(group, checkName(name), 0, null, 0, null);
}
/**
* Initializes a new platform {@code Thread}. This constructor has the same
* effect as {@linkplain #Thread(ThreadGroup,Runnable,String) Thread}
* {@code (null, task, name)}.
*
* <p> For a non-null task and name, invoking this constructor directly is
* equivalent to:
* <pre>{@code Thread.ofPlatform().name(name).unstarted(task); }</pre>
*
* @param task
* the object whose {@code run} method is invoked when this thread
* is started. If {@code null}, this thread's run method is invoked.
*
* @param name
* the name of the new thread
*
* @see <a href="#inheritance">Inheritance when creating threads</a>
*/
public Thread(Runnable task, String name) {
this(null, checkName(name), 0, task, 0, null);
}
/**
* Initializes a new platform {@code Thread} so that it has {@code task}
* as its run object, has the specified {@code name} as its name,
* and belongs to the thread group referred to by {@code group}.
*
* <p>If there is a security manager, its
* {@link SecurityManager#checkAccess(ThreadGroup) checkAccess}
* method is invoked with the ThreadGroup as its argument.
*
* <p>In addition, its {@code checkPermission} method is invoked with
* the {@code RuntimePermission("enableContextClassLoaderOverride")}
* permission when invoked directly or indirectly by the constructor
* of a subclass which overrides the {@code getContextClassLoader}
* or {@code setContextClassLoader} methods.
*
* <p>The priority of the newly created thread is the smaller of
* priority of the thread creating it and the maximum permitted
* priority of the thread group. The method {@linkplain #setPriority
* setPriority} may be used to change the priority to a new value.
*
* <p>The newly created thread is initially marked as being a daemon
* thread if and only if the thread creating it is currently marked
* as a daemon thread. The method {@linkplain #setDaemon setDaemon}
* may be used to change whether or not a thread is a daemon.
*
* <p>For a non-null group, task, and name, invoking this constructor directly
* is equivalent to:
* <pre>{@code Thread.ofPlatform().group(group).name(name).unstarted(task); }</pre>
*
* @param group
* the thread group. If {@code null} and there is a security
* manager, the group is determined by {@linkplain
* SecurityManager#getThreadGroup SecurityManager.getThreadGroup()}.
* If there is not a security manager or {@code
* SecurityManager.getThreadGroup()} returns {@code null}, the group
* is set to the current thread's thread group.
*
* @param task
* the object whose {@code run} method is invoked when this thread
* is started. If {@code null}, this thread's run method is invoked.
*
* @param name
* the name of the new thread
*
* @throws SecurityException
* if the current thread cannot create a thread in the specified
* thread group or cannot override the context class loader methods.
*
* @see <a href="#inheritance">Inheritance when creating threads</a>
*/
public Thread(ThreadGroup group, Runnable task, String name) {
this(group, checkName(name), 0, task, 0, null);
}
/**
* Initializes a new platform {@code Thread} so that it has {@code task}
* as its run object, has the specified {@code name} as its name,
* and belongs to the thread group referred to by {@code group}, and has
* the specified <i>stack size</i>.
*
* <p>This constructor is identical to {@link
* #Thread(ThreadGroup,Runnable,String)} with the exception of the fact
* that it allows the thread stack size to be specified. The stack size
* is the approximate number of bytes of address space that the virtual
* machine is to allocate for this thread's stack. <b>The effect of the
* {@code stackSize} parameter, if any, is highly platform dependent.</b>
*
* <p>On some platforms, specifying a higher value for the
* {@code stackSize} parameter may allow a thread to achieve greater
* recursion depth before throwing a {@link StackOverflowError}.
* Similarly, specifying a lower value may allow a greater number of
* threads to exist concurrently without throwing an {@link
* OutOfMemoryError} (or other internal error). The details of
* the relationship between the value of the {@code stackSize} parameter
* and the maximum recursion depth and concurrency level are
* platform-dependent. <b>On some platforms, the value of the
* {@code stackSize} parameter may have no effect whatsoever.</b>
*
* <p>The virtual machine is free to treat the {@code stackSize}
* parameter as a suggestion. If the specified value is unreasonably low
* for the platform, the virtual machine may instead use some
* platform-specific minimum value; if the specified value is unreasonably
* high, the virtual machine may instead use some platform-specific
* maximum. Likewise, the virtual machine is free to round the specified
* value up or down as it sees fit (or to ignore it completely).
*
* <p>Specifying a value of zero for the {@code stackSize} parameter will
* cause this constructor to behave exactly like the
* {@code Thread(ThreadGroup, Runnable, String)} constructor.
*
* <p><i>Due to the platform-dependent nature of the behavior of this
* constructor, extreme care should be exercised in its use.
* The thread stack size necessary to perform a given computation will
* likely vary from one JRE implementation to another. In light of this
* variation, careful tuning of the stack size parameter may be required,
* and the tuning may need to be repeated for each JRE implementation on
* which an application is to run.</i>
*
* <p>Implementation note: Java platform implementers are encouraged to
* document their implementation's behavior with respect to the
* {@code stackSize} parameter.
*
* <p>For a non-null group, task, and name, invoking this constructor directly
* is equivalent to:
* <pre>{@code Thread.ofPlatform().group(group).name(name).stackSize(stackSize).unstarted(task); }</pre>
*
* @param group
* the thread group. If {@code null} and there is a security
* manager, the group is determined by {@linkplain
* SecurityManager#getThreadGroup SecurityManager.getThreadGroup()}.
* If there is not a security manager or {@code
* SecurityManager.getThreadGroup()} returns {@code null}, the group
* is set to the current thread's thread group.
*
* @param task
* the object whose {@code run} method is invoked when this thread
* is started. If {@code null}, this thread's run method is invoked.
*
* @param name
* the name of the new thread
*
* @param stackSize
* the desired stack size for the new thread, or zero to indicate
* that this parameter is to be ignored.
*
* @throws SecurityException
* if the current thread cannot create a thread in the specified
* thread group
*
* @since 1.4
* @see <a href="#inheritance">Inheritance when creating threads</a>
*/
public Thread(ThreadGroup group, Runnable task, String name, long stackSize) {
this(group, checkName(name), 0, task, stackSize, null);
}
/**
* Initializes a new platform {@code Thread} so that it has {@code task}
* as its run object, has the specified {@code name} as its name,
* belongs to the thread group referred to by {@code group}, has
* the specified {@code stackSize}, and inherits initial values for
* {@linkplain InheritableThreadLocal inheritable thread-local} variables
* if {@code inheritThreadLocals} is {@code true}.
*
* <p> This constructor is identical to {@link
* #Thread(ThreadGroup,Runnable,String,long)} with the added ability to
* suppress, or not, the inheriting of initial values for inheritable
* thread-local variables from the constructing thread. This allows for
* finer grain control over inheritable thread-locals. Care must be taken
* when passing a value of {@code false} for {@code inheritThreadLocals},
* as it may lead to unexpected behavior if the new thread executes code
* that expects a specific thread-local value to be inherited.
*
* <p> Specifying a value of {@code true} for the {@code inheritThreadLocals}
* parameter will cause this constructor to behave exactly like the
* {@code Thread(ThreadGroup, Runnable, String, long)} constructor.
*
* <p> For a non-null group, task, and name, invoking this constructor directly
* is equivalent to:
* <pre>{@code Thread.ofPlatform()
* .group(group)
* .name(name)
* .stackSize(stackSize)
* .inheritInheritableThreadLocals(inheritInheritableThreadLocals)
* .unstarted(task); }</pre>
*
* @param group
* the thread group. If {@code null} and there is a security
* manager, the group is determined by {@linkplain
* SecurityManager#getThreadGroup SecurityManager.getThreadGroup()}.
* If there is not a security manager or {@code
* SecurityManager.getThreadGroup()} returns {@code null}, the group
* is set to the current thread's thread group.
*
* @param task
* the object whose {@code run} method is invoked when this thread
* is started. If {@code null}, this thread's run method is invoked.
*
* @param name
* the name of the new thread
*
* @param stackSize
* the desired stack size for the new thread, or zero to indicate
* that this parameter is to be ignored
*
* @param inheritInheritableThreadLocals
* if {@code true}, inherit initial values for inheritable
* thread-locals from the constructing thread, otherwise no initial
* values are inherited
*
* @throws SecurityException
* if the current thread cannot create a thread in the specified
* thread group
*
* @since 9
* @see <a href="#inheritance">Inheritance when creating threads</a>
*/
public Thread(ThreadGroup group, Runnable task, String name,
long stackSize, boolean inheritInheritableThreadLocals) {
this(group, checkName(name),
(inheritInheritableThreadLocals ? 0 : NO_INHERIT_THREAD_LOCALS),
task, stackSize, null);
}
/**
* Creates a virtual thread to execute a task and schedules it to execute.
*
* <p> This method is equivalent to:
* <pre>{@code Thread.ofVirtual().start(task); }</pre>
*
* @param task the object to run when the thread executes
* @return a new, and started, virtual thread
* @throws UnsupportedOperationException if preview features are not enabled
* @see <a href="#inheritance">Inheritance when creating threads</a>
* @since 19
*/
@PreviewFeature(feature = PreviewFeature.Feature.VIRTUAL_THREADS)
public static Thread startVirtualThread(Runnable task) {
Objects.requireNonNull(task);
PreviewFeatures.ensureEnabled();
var thread = ThreadBuilders.newVirtualThread(null, null, 0, task);
thread.start();
return thread;
}
/**
* Returns {@code true} if this thread is a virtual thread. A virtual thread
* is scheduled by the Java virtual machine rather than the operating system.
*
* @return {@code true} if this thread is a virtual thread
*
* @since 19
*/
@PreviewFeature(feature = PreviewFeature.Feature.VIRTUAL_THREADS)
public final boolean isVirtual() {
return (this instanceof BaseVirtualThread);
}
/**
* Schedules this thread to begin execution. The thread will execute
* independently of the current thread.
*
* <p> A thread can be started at most once. In particular, a thread can not
* be restarted after it has terminated.
*
* @throws IllegalThreadStateException if the thread was already started
*/
public void start() {
synchronized (this) {
// zero status corresponds to state "NEW".
if (holder.threadStatus != 0)
throw new IllegalThreadStateException();
start0();
}
}
/**
* Schedules this thread to begin execution in the given thread container.
* @throws IllegalStateException if the container is shutdown or closed
* @throws IllegalThreadStateException if the thread has already been started
*/
void start(ThreadContainer container) {
synchronized (this) {
// zero status corresponds to state "NEW".
if (holder.threadStatus != 0)
throw new IllegalThreadStateException();
// bind thread to container
setThreadContainer(container);
// start thread
boolean started = false;
container.onStart(this); // may throw
try {
// scoped values may be inherited
inheritScopedValueBindings(container);
start0();
started = true;
} finally {
if (!started) {
container.onExit(this);
}
}
}
}
private native void start0();
/**
* This method is run by the thread when it executes. Subclasses of {@code
* Thread} may override this method.
*
* <p> This method is not intended to be invoked directly. If this thread is a
* platform thread created with a {@link Runnable} task then invoking this method
* will invoke the task's {@code run} method. If this thread is a virtual thread
* then invoking this method directly does nothing.
*
* @implSpec The default implementation executes the {@link Runnable} task that
* the {@code Thread} was created with. If the thread was created without a task
* then this method does nothing.
*/
@Override
public void run() {
Runnable task = holder.task;
if (task != null) {
Object bindings = scopedValueBindings();
runWith(bindings, task);
}
}
/**
* The VM recognizes this method as special, so any changes to the
* name or signature require corresponding changes in
* JVM_FindScopedValueBindings().
*/
@Hidden
@ForceInline
private void runWith(Object bindings, Runnable op) {
ensureMaterializedForStackWalk(bindings);
op.run();
Reference.reachabilityFence(bindings);
}
/**
* Null out reference after Thread termination.
*/
void clearReferences() {
threadLocals = null;
inheritableThreadLocals = null;
inheritedAccessControlContext = null;
if (uncaughtExceptionHandler != null)
uncaughtExceptionHandler = null;
if (nioBlocker != null)
nioBlocker = null;
}
/**
* This method is called by the VM to give a Thread
* a chance to clean up before it actually exits.
*/
private void exit() {
// pop any remaining scopes from the stack, this may block
if (headStackableScopes != null) {
StackableScope.popAll();
}
// notify container that thread is exiting
ThreadContainer container = threadContainer();
if (container != null) {
container.onExit(this);
}
try {
if (threadLocals != null && TerminatingThreadLocal.REGISTRY.isPresent()) {
TerminatingThreadLocal.threadTerminated();
}
} finally {
clearReferences();
}
}
/**
* Throws {@code UnsupportedOperationException}.
*
* @throws UnsupportedOperationException always
*
* @deprecated This method was originally specified to "stop" a victim
* thread by causing the victim thread to throw a {@link ThreadDeath}.
* It was inherently unsafe. Stopping a thread caused it to unlock
* all of the monitors that it had locked (as a natural consequence
* of the {@code ThreadDeath} exception propagating up the stack). If
* any of the objects previously protected by these monitors were in
* an inconsistent state, the damaged objects became visible to
* other threads, potentially resulting in arbitrary behavior.
* Usages of {@code stop} should be replaced by code that simply
* modifies some variable to indicate that the target thread should
* stop running. The target thread should check this variable
* regularly, and return from its run method in an orderly fashion
* if the variable indicates that it is to stop running. If the
* target thread waits for long periods (on a condition variable,
* for example), the {@code interrupt} method should be used to
* interrupt the wait.
* For more information, see
* <a href="{@docRoot}/java.base/java/lang/doc-files/threadPrimitiveDeprecation.html">Why
* are Thread.stop, Thread.suspend and Thread.resume Deprecated?</a>.
*/
@Deprecated(since="1.2", forRemoval=true)
public final void stop() {
throw new UnsupportedOperationException();
}
/**
* Interrupts this thread.
*
* <p> Unless the current thread is interrupting itself, which is
* always permitted, the {@link #checkAccess() checkAccess} method
* of this thread is invoked, which may cause a {@link
* SecurityException} to be thrown.
*
* <p> If this thread is blocked in an invocation of the {@link
* Object#wait() wait()}, {@link Object#wait(long) wait(long)}, or {@link
* Object#wait(long, int) wait(long, int)} methods of the {@link Object}
* class, or of the {@link #join()}, {@link #join(long)}, {@link
* #join(long, int)}, {@link #sleep(long)}, or {@link #sleep(long, int)}
* methods of this class, then its interrupt status will be cleared and it
* will receive an {@link InterruptedException}.
*
* <p> If this thread is blocked in an I/O operation upon an {@link
* java.nio.channels.InterruptibleChannel InterruptibleChannel}
* then the channel will be closed, the thread's interrupt
* status will be set, and the thread will receive a {@link
* java.nio.channels.ClosedByInterruptException}.
*
* <p> If this thread is blocked in a {@link java.nio.channels.Selector}
* then the thread's interrupt status will be set and it will return
* immediately from the selection operation, possibly with a non-zero
* value, just as if the selector's {@link
* java.nio.channels.Selector#wakeup wakeup} method were invoked.
*
* <p> If none of the previous conditions hold then this thread's interrupt
* status will be set. </p>
*
* <p> Interrupting a thread that is not alive need not have any effect.
*
* @implNote In the JDK Reference Implementation, interruption of a thread
* that is not alive still records that the interrupt request was made and
* will report it via {@link #interrupted} and {@link #isInterrupted()}.
*
* @throws SecurityException
* if the current thread cannot modify this thread
*
* @revised 6.0, 14
*/
public void interrupt() {
if (this != Thread.currentThread()) {
checkAccess();
// thread may be blocked in an I/O operation
synchronized (interruptLock) {
Interruptible b = nioBlocker;
if (b != null) {
interrupted = true;
interrupt0(); // inform VM of interrupt
b.interrupt(this);
return;
}
}
}
interrupted = true;
interrupt0(); // inform VM of interrupt
}
/**
* Tests whether the current thread has been interrupted. The
* <i>interrupted status</i> of the thread is cleared by this method. In
* other words, if this method were to be called twice in succession, the
* second call would return false (unless the current thread were
* interrupted again, after the first call had cleared its interrupted
* status and before the second call had examined it).
*
* @return {@code true} if the current thread has been interrupted;
* {@code false} otherwise.
* @see #isInterrupted()
* @revised 6.0, 14
*/
public static boolean interrupted() {
return currentThread().getAndClearInterrupt();
}
/**
* Tests whether this thread has been interrupted. The <i>interrupted
* status</i> of the thread is unaffected by this method.
*
* @return {@code true} if this thread has been interrupted;
* {@code false} otherwise.
* @see #interrupted()
* @revised 6.0, 14
*/
public boolean isInterrupted() {
return interrupted;
}
final void setInterrupt() {
// assert Thread.currentCarrierThread() == this;
if (!interrupted) {
interrupted = true;
interrupt0(); // inform VM of interrupt
}
}
final void clearInterrupt() {
// assert Thread.currentCarrierThread() == this;
if (interrupted) {
interrupted = false;
clearInterruptEvent();
}
}
boolean getAndClearInterrupt() {
boolean oldValue = interrupted;
// We may have been interrupted the moment after we read the field,
// so only clear the field if we saw that it was set and will return
// true; otherwise we could lose an interrupt.
if (oldValue) {
interrupted = false;
clearInterruptEvent();
}
return oldValue;
}
/**
* Tests if this thread is alive. A thread is alive if it has
* been started and has not yet terminated.
*
* @return {@code true} if this thread is alive;
* {@code false} otherwise.
*/
public final boolean isAlive() {
return alive();
}
/**
* Returns true if this thread is alive.
* This method is non-final so it can be overridden.
*/
boolean alive() {
return isAlive0();
}
private native boolean isAlive0();
/**
* Throws {@code UnsupportedOperationException}.
*
* @throws UnsupportedOperationException always
*
* @deprecated This method was originally specified to suspend a thread.
* It was inherently deadlock-prone. If the target thread held a lock on
* a monitor protecting a critical system resource when it was suspended,
* no thread could access the resource until the target thread was resumed.
* If the thread intending to resume the target thread attempted to lock
* the monitor prior to calling {@code resume}, deadlock would result.
* Such deadlocks typically manifested themselves as "frozen" processes.
* For more information, see
* <a href="{@docRoot}/java.base/java/lang/doc-files/threadPrimitiveDeprecation.html">Why
* are Thread.stop, Thread.suspend and Thread.resume Deprecated?</a>.
*/
@Deprecated(since="1.2", forRemoval=true)
public final void suspend() {
throw new UnsupportedOperationException();
}
/**
* Throws {@code UnsupportedOperationException}.
*
* @throws UnsupportedOperationException always
*
* @deprecated This method was originally specified to resume a thread
* suspended with {@link #suspend()}. Suspending a thread was
* inherently deadlock-prone.
* For more information, see
* <a href="{@docRoot}/java.base/java/lang/doc-files/threadPrimitiveDeprecation.html">Why
* are Thread.stop, Thread.suspend and Thread.resume Deprecated?</a>.
*/
@Deprecated(since="1.2", forRemoval=true)
public final void resume() {
throw new UnsupportedOperationException();
}
/**
* Changes the priority of this thread.
*
* For platform threads, the priority is set to the smaller of the specified
* {@code newPriority} and the maximum permitted priority of the thread's
* {@linkplain ThreadGroup thread group}.
*
* The priority of a virtual thread is always {@link Thread#NORM_PRIORITY}
* and {@code newPriority} is ignored.
*
* @param newPriority the new thread priority
* @throws IllegalArgumentException if the priority is not in the
* range {@code MIN_PRIORITY} to {@code MAX_PRIORITY}.
* @throws SecurityException
* if {@link #checkAccess} determines that the current
* thread cannot modify this thread
* @see #setPriority(int)
* @see ThreadGroup#getMaxPriority()
*/
public final void setPriority(int newPriority) {
checkAccess();
if (newPriority > MAX_PRIORITY || newPriority < MIN_PRIORITY) {
throw new IllegalArgumentException();
}
if (!isVirtual()) {
priority(newPriority);
}
}
void priority(int newPriority) {
ThreadGroup g = holder.group;
if (g != null) {
int maxPriority = g.getMaxPriority();
if (newPriority > maxPriority) {
newPriority = maxPriority;
}
setPriority0(holder.priority = newPriority);
}
}
/**
* Returns this thread's priority.
*
* <p> The priority of a virtual thread is always {@link Thread#NORM_PRIORITY}.
*
* @return this thread's priority.
* @see #setPriority
*/
public final int getPriority() {
if (isVirtual()) {
return Thread.NORM_PRIORITY;
} else {
return holder.priority;
}
}
/**
* Changes the name of this thread to be equal to the argument {@code name}.
* <p>
* First the {@code checkAccess} method of this thread is called
* with no arguments. This may result in throwing a
* {@code SecurityException}.
*
* @implNote In the JDK Reference Implementation, if this thread is the
* current thread, and it's a platform thread that was not attached to the
* VM with the Java Native Interface
* <a href="{@docRoot}/../specs/jni/invocation.html#attachcurrentthread">
* AttachCurrentThread</a> function, then this method will set the operating
* system thread name. This may be useful for debugging and troubleshooting
* purposes.
*
* @param name the new name for this thread.
* @throws SecurityException if the current thread cannot modify this
* thread.
* @see #getName
* @see #checkAccess()
*/
public final synchronized void setName(String name) {
checkAccess();
if (name == null) {
throw new NullPointerException("name cannot be null");
}
this.name = name;
if (!isVirtual() && Thread.currentThread() == this) {
setNativeName(name);
}
}
/**
* Returns this thread's name.
*
* @return this thread's name.
* @see #setName(String)
*/
public final String getName() {
return name;
}
/**
* Returns the thread's thread group or {@code null} if the thread has
* terminated.
*
* <p> The thread group returned for a virtual thread is the special
* <a href="ThreadGroup.html#virtualthreadgroup"><em>ThreadGroup for
* virtual threads</em></a>.
*
* @return this thread's thread group or {@code null}
*/
public final ThreadGroup getThreadGroup() {
if (isTerminated()) {
return null;
} else {
return isVirtual() ? virtualThreadGroup() : holder.group;
}
}
/**
* Returns an estimate of the number of {@linkplain #isAlive() live}
* platform threads in the current thread's thread group and its subgroups.
* Virtual threads are not included in the estimate.
*
* <p> The value returned is only an estimate because the number of
* threads may change dynamically while this method traverses internal
* data structures, and might be affected by the presence of certain
* system threads. This method is intended primarily for debugging
* and monitoring purposes.
*
* @return an estimate of the number of live platform threads in the
* current thread's thread group and in any other thread group
* that has the current thread's thread group as an ancestor
*/
public static int activeCount() {
return currentThread().getThreadGroup().activeCount();
}
/**
* Copies into the specified array every {@linkplain #isAlive() live}
* platform thread in the current thread's thread group and its subgroups.
* This method simply invokes the {@link java.lang.ThreadGroup#enumerate(Thread[])}
* method of the current thread's thread group. Virtual threads are
* not enumerated by this method.
*
* <p> An application might use the {@linkplain #activeCount activeCount}
* method to get an estimate of how big the array should be, however
* <i>if the array is too short to hold all the threads, the extra threads
* are silently ignored.</i> If it is critical to obtain every live
* thread in the current thread's thread group and its subgroups, the
* invoker should verify that the returned int value is strictly less
* than the length of {@code tarray}.
*
* <p> Due to the inherent race condition in this method, it is recommended
* that the method only be used for debugging and monitoring purposes.
*
* @param tarray
* an array into which to put the list of threads
*
* @return the number of threads put into the array
*
* @throws SecurityException
* if {@link java.lang.ThreadGroup#checkAccess} determines that
* the current thread cannot access its thread group
*/
public static int enumerate(Thread[] tarray) {
return currentThread().getThreadGroup().enumerate(tarray);
}
/**
* Throws {@code UnsupportedOperationException}.
*
* @return nothing
*
* @deprecated This method was originally designed to count the number of
* stack frames but the results were never well-defined and it
* depended on thread-suspension.
* This method is subject to removal in a future version of Java SE.
* @see StackWalker
*/
@Deprecated(since="1.2", forRemoval=true)
public int countStackFrames() {
throw new UnsupportedOperationException();
}
/**
* Waits at most {@code millis} milliseconds for this thread to terminate.
* A timeout of {@code 0} means to wait forever.
* This method returns immediately, without waiting, if the thread has not
* been {@link #start() started}.
*
* @implNote
* For platform threads, the implementation uses a loop of {@code this.wait}
* calls conditioned on {@code this.isAlive}. As a thread terminates the
* {@code this.notifyAll} method is invoked. It is recommended that
* applications not use {@code wait}, {@code notify}, or
* {@code notifyAll} on {@code Thread} instances.
*
* @param millis
* the time to wait in milliseconds
*
* @throws IllegalArgumentException
* if the value of {@code millis} is negative
*
* @throws InterruptedException
* if any thread has interrupted the current thread. The
* <i>interrupted status</i> of the current thread is
* cleared when this exception is thrown.
*/
public final void join(long millis) throws InterruptedException {
if (millis < 0)
throw new IllegalArgumentException("timeout value is negative");
if (this instanceof VirtualThread vthread) {
if (isAlive()) {
long nanos = MILLISECONDS.toNanos(millis);
vthread.joinNanos(nanos);
}
return;
}
synchronized (this) {
if (millis > 0) {
if (isAlive()) {
final long startTime = System.nanoTime();
long delay = millis;
do {
wait(delay);
} while (isAlive() && (delay = millis -
NANOSECONDS.toMillis(System.nanoTime() - startTime)) > 0);
}
} else {
while (isAlive()) {
wait(0);
}
}
}
}
/**
* Waits at most {@code millis} milliseconds plus
* {@code nanos} nanoseconds for this thread to terminate.
* If both arguments are {@code 0}, it means to wait forever.
* This method returns immediately, without waiting, if the thread has not
* been {@link #start() started}.
*
* @implNote
* For platform threads, the implementation uses a loop of {@code this.wait}
* calls conditioned on {@code this.isAlive}. As a thread terminates the
* {@code this.notifyAll} method is invoked. It is recommended that
* applications not use {@code wait}, {@code notify}, or
* {@code notifyAll} on {@code Thread} instances.
*
* @param millis
* the time to wait in milliseconds
*
* @param nanos
* {@code 0-999999} additional nanoseconds to wait
*
* @throws IllegalArgumentException
* if the value of {@code millis} is negative, or the value
* of {@code nanos} is not in the range {@code 0-999999}
*
* @throws InterruptedException
* if any thread has interrupted the current thread. The
* <i>interrupted status</i> of the current thread is
* cleared when this exception is thrown.
*/
public final void join(long millis, int nanos) throws InterruptedException {
if (millis < 0) {
throw new IllegalArgumentException("timeout value is negative");
}
if (nanos < 0 || nanos > 999999) {
throw new IllegalArgumentException("nanosecond timeout value out of range");
}
if (this instanceof VirtualThread vthread) {
if (isAlive()) {
// convert arguments to a total in nanoseconds
long totalNanos = MILLISECONDS.toNanos(millis);
totalNanos += Math.min(Long.MAX_VALUE - totalNanos, nanos);
vthread.joinNanos(totalNanos);
}
return;
}
if (nanos > 0 && millis < Long.MAX_VALUE) {
millis++;
}
join(millis);
}
/**
* Waits for this thread to terminate.
*
* <p> An invocation of this method behaves in exactly the same
* way as the invocation
*
* <blockquote>
* {@linkplain #join(long) join}{@code (0)}
* </blockquote>
*
* @throws InterruptedException
* if any thread has interrupted the current thread. The
* <i>interrupted status</i> of the current thread is
* cleared when this exception is thrown.
*/
public final void join() throws InterruptedException {
join(0);
}
/**
* Waits for this thread to terminate for up to the given waiting duration.
*
* <p> This method does not wait if the duration to wait is less than or
* equal to zero. In this case, the method just tests if the thread has
* terminated.
*
* @param duration
* the maximum duration to wait
*
* @return {@code true} if the thread has terminated, {@code false} if the
* thread has not terminated
*
* @throws InterruptedException
* if the current thread is interrupted while waiting.
* The <i>interrupted status</i> of the current thread is cleared
* when this exception is thrown.
*
* @throws IllegalThreadStateException
* if this thread has not been started.
*
* @since 19
*/
public final boolean join(Duration duration) throws InterruptedException {
long nanos = NANOSECONDS.convert(duration); // MAX_VALUE if > 292 years
Thread.State state = threadState();
if (state == State.NEW)
throw new IllegalThreadStateException("Thread not started");
if (state == State.TERMINATED)
return true;
if (nanos <= 0)
return false;
if (this instanceof VirtualThread vthread) {
return vthread.joinNanos(nanos);
}
// convert to milliseconds
long millis = MILLISECONDS.convert(nanos, NANOSECONDS);
if (nanos > NANOSECONDS.convert(millis, MILLISECONDS)) {
millis += 1L;
}
join(millis);
return isTerminated();
}
/**
* Prints a stack trace of the current thread to the standard error stream.
* This method is useful for debugging.
*/
public static void dumpStack() {
new Exception("Stack trace").printStackTrace();
}
/**
* Marks this thread as either a <i>daemon</i> or <i>non-daemon</i> thread.
* The <a href="Runtime.html#shutdown">shutdown sequence</a> begins when all
* started non-daemon threads have terminated.
*
* <p> The daemon status of a virtual thread is always {@code true} and cannot be
* changed by this method to {@code false}.
*
* <p> This method must be invoked before the thread is started. The behavior
* of this method when the thread has terminated is not specified.
*
* @param on
* if {@code true}, marks this thread as a daemon thread
*
* @throws IllegalArgumentException
* if this is a virtual thread and {@code on} is false
* @throws IllegalThreadStateException
* if this thread is {@linkplain #isAlive alive}
* @throws SecurityException
* if {@link #checkAccess} determines that the current
* thread cannot modify this thread
*/
public final void setDaemon(boolean on) {
checkAccess();
if (isVirtual() && !on)
throw new IllegalArgumentException("'false' not legal for virtual threads");
if (isAlive())
throw new IllegalThreadStateException();
if (!isVirtual())
daemon(on);
}
void daemon(boolean on) {
holder.daemon = on;
}
/**
* Tests if this thread is a daemon thread.
* The daemon status of a virtual thread is always {@code true}.
*
* @return {@code true} if this thread is a daemon thread;
* {@code false} otherwise.
* @see #setDaemon(boolean)
*/
public final boolean isDaemon() {
if (isVirtual()) {
return true;
} else {
return holder.daemon;
}
}
/**
* Determines if the currently running thread has permission to
* modify this thread.
* <p>
* If there is a security manager, its {@code checkAccess} method
* is called with this thread as its argument. This may result in
* throwing a {@code SecurityException}.
*
* @throws SecurityException if the current thread is not allowed to
* access this thread.
* @see SecurityManager#checkAccess(Thread)
* @deprecated This method is only useful in conjunction with
* {@linkplain SecurityManager the Security Manager}, which is
* deprecated and subject to removal in a future release.
* Consequently, this method is also deprecated and subject to
* removal. There is no replacement for the Security Manager or this
* method.
*/
@Deprecated(since="17", forRemoval=true)
public final void checkAccess() {
@SuppressWarnings("removal")
SecurityManager security = System.getSecurityManager();
if (security != null) {
security.checkAccess(this);
}
}
/**
* Returns a string representation of this thread. The string representation
* will usually include the thread's {@linkplain #threadId() identifier} and
* name. The default implementation for platform threads includes the thread's
* identifier, name, priority, and the name of the thread group.
*
* @return a string representation of this thread.
*/
public String toString() {
StringBuilder sb = new StringBuilder("Thread[#");
sb.append(threadId());
sb.append(",");
sb.append(getName());
sb.append(",");
sb.append(getPriority());
sb.append(",");
ThreadGroup group = getThreadGroup();
if (group != null)
sb.append(group.getName());
sb.append("]");
return sb.toString();
}
/**
* Returns the context {@code ClassLoader} for this thread.
* The context {@code ClassLoader} may be set by the creator of the thread
* for use by code running in this thread when loading classes and resources.
* If not {@linkplain #setContextClassLoader set}, the default is to inherit
* the context class loader from the parent thread.
*
* <p> The context {@code ClassLoader} of the primordial thread is typically
* set to the class loader used to load the application.
*
* @return the context {@code ClassLoader} for this thread, or {@code null}
* indicating the system class loader (or, failing that, the
* bootstrap class loader)
*
* @throws SecurityException
* if a security manager is present, and the caller's class loader
* is not {@code null} and is not the same as or an ancestor of the
* context class loader, and the caller does not have the
* {@link RuntimePermission}{@code ("getClassLoader")}
*
* @since 1.2
*/
@CallerSensitive
public ClassLoader getContextClassLoader() {
ClassLoader cl = this.contextClassLoader;
if (cl == null)
return null;
if (!isSupportedClassLoader(cl))
cl = ClassLoader.getSystemClassLoader();
@SuppressWarnings("removal")
SecurityManager sm = System.getSecurityManager();
if (sm != null) {
Class<?> caller = Reflection.getCallerClass();
ClassLoader.checkClassLoaderPermission(cl, caller);
}
return cl;
}
/**
* Sets the context {@code ClassLoader} for this thread.
*
* <p> The context {@code ClassLoader} may be set by the creator of the thread
* for use by code running in this thread when loading classes and resources.
*
* <p> The context {@code ClassLoader} cannot be set when the thread is
* {@linkplain Thread.Builder#allowSetThreadLocals(boolean) not allowed} to have
* its own copy of thread local variables.
*
* <p> If a security manager is present, its {@link
* SecurityManager#checkPermission(java.security.Permission) checkPermission}
* method is invoked with a {@link RuntimePermission RuntimePermission}{@code
* ("setContextClassLoader")} permission to see if setting the context
* ClassLoader is permitted.
*
* @param cl
* the context ClassLoader for this Thread, or null indicating the
* system class loader (or, failing that, the bootstrap class loader)
*
* @throws UnsupportedOperationException if this thread is not allowed
* to set values for its copy of thread-local variables
*
* @throws SecurityException
* if the current thread cannot set the context ClassLoader
*
* @since 1.2
*/
public void setContextClassLoader(ClassLoader cl) {
@SuppressWarnings("removal")
SecurityManager sm = System.getSecurityManager();
if (sm != null) {
sm.checkPermission(new RuntimePermission("setContextClassLoader"));
}
if (!isSupportedClassLoader(contextClassLoader)) {
throw new UnsupportedOperationException(
"The context class loader cannot be set");
}
contextClassLoader = cl;
}
/**
* Returns true if the given ClassLoader is a "supported" class loader. All
* class loaders, except ClassLoaders.NOT_SUPPORTED, are considered supported.
* This method allows the initialization of ClassLoaders to be delayed until
* it is required.
*/
private static boolean isSupportedClassLoader(ClassLoader loader) {
if (loader == null)
return true;
if (loader == jdk.internal.loader.ClassLoaders.appClassLoader())
return true;
return loader != Constants.NOT_SUPPORTED_CLASSLOADER;
}
/**
* Returns {@code true} if and only if the current thread holds the
* monitor lock on the specified object.
*
* <p>This method is designed to allow a program to assert that
* the current thread already holds a specified lock:
* <pre>
* assert Thread.holdsLock(obj);
* </pre>
*
* @param obj the object on which to test lock ownership
* @return {@code true} if the current thread holds the monitor lock on
* the specified object.
* @since 1.4
*/
public static native boolean holdsLock(Object obj);
private static final StackTraceElement[] EMPTY_STACK_TRACE
= new StackTraceElement[0];
/**
* Returns an array of stack trace elements representing the stack dump
* of this thread. This method will return a zero-length array if
* this thread has not started, has started but has not yet been
* scheduled to run by the system, or has terminated.
* If the returned array is of non-zero length then the first element of
* the array represents the top of the stack, which is the most recent
* method invocation in the sequence. The last element of the array
* represents the bottom of the stack, which is the least recent method
* invocation in the sequence.
*
* <p>If there is a security manager, and this thread is not
* the current thread, then the security manager's
* {@code checkPermission} method is called with a
* {@code RuntimePermission("getStackTrace")} permission
* to see if it's ok to get the stack trace.
*
* <p>Some virtual machines may, under some circumstances, omit one
* or more stack frames from the stack trace. In the extreme case,
* a virtual machine that has no stack trace information concerning
* this thread is permitted to return a zero-length array from this
* method.
*
* @return an array of {@code StackTraceElement},
* each represents one stack frame.
*
* @throws SecurityException
* if a security manager exists and its
* {@code checkPermission} method doesn't allow
* getting the stack trace of thread.
* @see Throwable#getStackTrace
*
* @since 1.5
*/
public StackTraceElement[] getStackTrace() {
if (this != Thread.currentThread()) {
// check for getStackTrace permission
@SuppressWarnings("removal")
SecurityManager security = System.getSecurityManager();
if (security != null) {
security.checkPermission(SecurityConstants.GET_STACK_TRACE_PERMISSION);
}
// optimization so we do not call into the vm for threads that
// have not yet started or have terminated
if (!isAlive()) {
return EMPTY_STACK_TRACE;
}
StackTraceElement[] stackTrace = asyncGetStackTrace();
return (stackTrace != null) ? stackTrace : EMPTY_STACK_TRACE;
} else {
return (new Exception()).getStackTrace();
}
}
/**
* Returns an array of stack trace elements representing the stack dump of
* this thread. Returns null if the stack trace cannot be obtained. In
* the default implementation, null is returned if the thread is a virtual
* thread that is not mounted or the thread is a platform thread that has
* terminated.
*/
StackTraceElement[] asyncGetStackTrace() {
Object stackTrace = getStackTrace0();
if (stackTrace == null) {
return null;
}
StackTraceElement[] stes = (StackTraceElement[]) stackTrace;
if (stes.length == 0) {
return null;
} else {
return StackTraceElement.of(stes);
}
}
private native Object getStackTrace0();
/**
* Returns a map of stack traces for all live platform threads. The map
* does not include virtual threads.
* The map keys are threads and each map value is an array of
* {@code StackTraceElement} that represents the stack dump
* of the corresponding {@code Thread}.
* The returned stack traces are in the format specified for
* the {@link #getStackTrace getStackTrace} method.
*
* <p>The threads may be executing while this method is called.
* The stack trace of each thread only represents a snapshot and
* each stack trace may be obtained at different time. A zero-length
* array will be returned in the map value if the virtual machine has
* no stack trace information about a thread.
*
* <p>If there is a security manager, then the security manager's
* {@code checkPermission} method is called with a
* {@code RuntimePermission("getStackTrace")} permission as well as
* {@code RuntimePermission("modifyThreadGroup")} permission
* to see if it is ok to get the stack trace of all threads.
*
* @return a {@code Map} from {@code Thread} to an array of
* {@code StackTraceElement} that represents the stack trace of
* the corresponding thread.
*
* @throws SecurityException
* if a security manager exists and its
* {@code checkPermission} method doesn't allow
* getting the stack trace of thread.
* @see #getStackTrace
* @see Throwable#getStackTrace
*
* @since 1.5
*/
public static Map<Thread, StackTraceElement[]> getAllStackTraces() {
// check for getStackTrace permission
@SuppressWarnings("removal")
SecurityManager security = System.getSecurityManager();
if (security != null) {
security.checkPermission(SecurityConstants.GET_STACK_TRACE_PERMISSION);
security.checkPermission(SecurityConstants.MODIFY_THREADGROUP_PERMISSION);
}
// Get a snapshot of the list of all threads
Thread[] threads = getThreads();
StackTraceElement[][] traces = dumpThreads(threads);
Map<Thread, StackTraceElement[]> m = HashMap.newHashMap(threads.length);
for (int i = 0; i < threads.length; i++) {
Thread thread = threads[i];
StackTraceElement[] stackTrace = traces[i];
// BoundVirtualThread objects may be in list returned by the VM
if (!thread.isVirtual() && stackTrace != null) {
m.put(threads[i], stackTrace);
}
// else terminated so we don't put it in the map
}
return m;
}
/** cache of subclass security audit results */
private static class Caches {
/** cache of subclass security audit results */
static final ClassValue<Boolean> subclassAudits =
new ClassValue<>() {
@Override
protected Boolean computeValue(Class<?> type) {
return auditSubclass(type);
}
};
}
/**
* Verifies that this (possibly subclass) instance can be constructed
* without violating security constraints: the subclass must not override
* security-sensitive non-final methods, or else the
* "enableContextClassLoaderOverride" RuntimePermission is checked.
*/
private static boolean isCCLOverridden(Class<?> cl) {
if (cl == Thread.class)
return false;
return Caches.subclassAudits.get(cl);
}
/**
* Performs reflective checks on given subclass to verify that it doesn't
* override security-sensitive non-final methods. Returns true if the
* subclass overrides any of the methods, false otherwise.
*/
private static boolean auditSubclass(final Class<?> subcl) {
@SuppressWarnings("removal")
Boolean result = AccessController.doPrivileged(
new PrivilegedAction<>() {
public Boolean run() {
for (Class<?> cl = subcl;
cl != Thread.class;
cl = cl.getSuperclass())
{
try {
cl.getDeclaredMethod("getContextClassLoader", new Class<?>[0]);
return Boolean.TRUE;
} catch (NoSuchMethodException ex) {
}
try {
Class<?>[] params = {ClassLoader.class};
cl.getDeclaredMethod("setContextClassLoader", params);
return Boolean.TRUE;
} catch (NoSuchMethodException ex) {
}
}
return Boolean.FALSE;
}
}
);
return result.booleanValue();
}
/**
* Return an array of all live threads.
*/
static Thread[] getAllThreads() {
Thread[] threads = getThreads();
return Stream.of(threads)
// BoundVirtualThread objects may be in list returned by the VM
.filter(Predicate.not(Thread::isVirtual))
.toArray(Thread[]::new);
}
private static native StackTraceElement[][] dumpThreads(Thread[] threads);
private static native Thread[] getThreads();
/**
* Returns the identifier of this Thread. The thread ID is a positive
* {@code long} number generated when this thread was created.
* The thread ID is unique and remains unchanged during its lifetime.
*
* @return this thread's ID
*
* @deprecated This method is not final and may be overridden to return a
* value that is not the thread ID. Use {@link #threadId()} instead.
*
* @since 1.5
*/
@Deprecated(since="19")
public long getId() {
return threadId();
}
/**
* Returns the identifier of this Thread. The thread ID is a positive
* {@code long} number generated when this thread was created.
* The thread ID is unique and remains unchanged during its lifetime.
*
* @return this thread's ID
* @since 19
*/
public final long threadId() {
return tid;
}
/**
* A thread state. A thread can be in one of the following states:
* <ul>
* <li>{@link #NEW}<br>
* A thread that has not yet started is in this state.
* </li>
* <li>{@link #RUNNABLE}<br>
* A thread executing in the Java virtual machine is in this state.
* </li>
* <li>{@link #BLOCKED}<br>
* A thread that is blocked waiting for a monitor lock
* is in this state.
* </li>
* <li>{@link #WAITING}<br>
* A thread that is waiting indefinitely for another thread to
* perform a particular action is in this state.
* </li>
* <li>{@link #TIMED_WAITING}<br>
* A thread that is waiting for another thread to perform an action
* for up to a specified waiting time is in this state.
* </li>
* <li>{@link #TERMINATED}<br>
* A thread that has exited is in this state.
* </li>
* </ul>
*
* <p>
* A thread can be in only one state at a given point in time.
* These states are virtual machine states which do not reflect
* any operating system thread states.
*
* @since 1.5
* @see #getState
*/
public enum State {
/**
* Thread state for a thread which has not yet started.
*/
NEW,
/**
* Thread state for a runnable thread. A thread in the runnable
* state is executing in the Java virtual machine but it may
* be waiting for other resources from the operating system
* such as processor.
*/
RUNNABLE,
/**
* Thread state for a thread blocked waiting for a monitor lock.
* A thread in the blocked state is waiting for a monitor lock
* to enter a synchronized block/method or
* reenter a synchronized block/method after calling
* {@link Object#wait() Object.wait}.
*/
BLOCKED,
/**
* Thread state for a waiting thread.
* A thread is in the waiting state due to calling one of the
* following methods:
* <ul>
* <li>{@link Object#wait() Object.wait} with no timeout</li>
* <li>{@link #join() Thread.join} with no timeout</li>
* <li>{@link LockSupport#park() LockSupport.park}</li>
* </ul>
*
* <p>A thread in the waiting state is waiting for another thread to
* perform a particular action.
*
* For example, a thread that has called {@code Object.wait()}
* on an object is waiting for another thread to call
* {@code Object.notify()} or {@code Object.notifyAll()} on
* that object. A thread that has called {@code Thread.join()}
* is waiting for a specified thread to terminate.
*/
WAITING,
/**
* Thread state for a waiting thread with a specified waiting time.
* A thread is in the timed waiting state due to calling one of
* the following methods with a specified positive waiting time:
* <ul>
* <li>{@link #sleep Thread.sleep}</li>
* <li>{@link Object#wait(long) Object.wait} with timeout</li>
* <li>{@link #join(long) Thread.join} with timeout</li>
* <li>{@link LockSupport#parkNanos LockSupport.parkNanos}</li>
* <li>{@link LockSupport#parkUntil LockSupport.parkUntil}</li>
* </ul>
*/
TIMED_WAITING,
/**
* Thread state for a terminated thread.
* The thread has completed execution.
*/
TERMINATED;
}
/**
* Returns the state of this thread.
* This method is designed for use in monitoring of the system state,
* not for synchronization control.
*
* @return this thread's state.
* @since 1.5
*/
public State getState() {
return threadState();
}
/**
* Returns the state of this thread.
* This method can be used instead of getState as getState is not final and
* so can be overridden to run arbitrary code.
*/
State threadState() {
return jdk.internal.misc.VM.toThreadState(holder.threadStatus);
}
/**
* Returns true if the thread has terminated.
*/
boolean isTerminated() {
return threadState() == State.TERMINATED;
}
/**
* Interface for handlers invoked when a {@code Thread} abruptly
* terminates due to an uncaught exception.
* <p>When a thread is about to terminate due to an uncaught exception
* the Java Virtual Machine will query the thread for its
* {@code UncaughtExceptionHandler} using
* {@link #getUncaughtExceptionHandler} and will invoke the handler's
* {@code uncaughtException} method, passing the thread and the
* exception as arguments.
* If a thread has not had its {@code UncaughtExceptionHandler}
* explicitly set, then its {@code ThreadGroup} object acts as its
* {@code UncaughtExceptionHandler}. If the {@code ThreadGroup} object
* has no
* special requirements for dealing with the exception, it can forward
* the invocation to the {@linkplain #getDefaultUncaughtExceptionHandler
* default uncaught exception handler}.
*
* @see #setDefaultUncaughtExceptionHandler
* @see #setUncaughtExceptionHandler
* @see ThreadGroup#uncaughtException
* @since 1.5
*/
@FunctionalInterface
public interface UncaughtExceptionHandler {
/**
* Method invoked when the given thread terminates due to the
* given uncaught exception.
* <p>Any exception thrown by this method will be ignored by the
* Java Virtual Machine.
* @param t the thread
* @param e the exception
*/
void uncaughtException(Thread t, Throwable e);
}
// null unless explicitly set
private volatile UncaughtExceptionHandler uncaughtExceptionHandler;
// null unless explicitly set
private static volatile UncaughtExceptionHandler defaultUncaughtExceptionHandler;
/**
* Set the default handler invoked when a thread abruptly terminates
* due to an uncaught exception, and no other handler has been defined
* for that thread.
*
* <p>Uncaught exception handling is controlled first by the thread, then
* by the thread's {@link ThreadGroup} object and finally by the default
* uncaught exception handler. If the thread does not have an explicit
* uncaught exception handler set, and the thread's thread group
* (including parent thread groups) does not specialize its
* {@code uncaughtException} method, then the default handler's
* {@code uncaughtException} method will be invoked.
* <p>By setting the default uncaught exception handler, an application
* can change the way in which uncaught exceptions are handled (such as
* logging to a specific device, or file) for those threads that would
* already accept whatever &quot;default&quot; behavior the system
* provided.
*
* <p>Note that the default uncaught exception handler should not usually
* defer to the thread's {@code ThreadGroup} object, as that could cause
* infinite recursion.
*
* @param ueh the object to use as the default uncaught exception handler.
* If {@code null} then there is no default handler.
*
* @throws SecurityException if a security manager is present and it denies
* {@link RuntimePermission}{@code ("setDefaultUncaughtExceptionHandler")}
*
* @see #setUncaughtExceptionHandler
* @see #getUncaughtExceptionHandler
* @see ThreadGroup#uncaughtException
* @since 1.5
*/
public static void setDefaultUncaughtExceptionHandler(UncaughtExceptionHandler ueh) {
@SuppressWarnings("removal")
SecurityManager sm = System.getSecurityManager();
if (sm != null) {
sm.checkPermission(
new RuntimePermission("setDefaultUncaughtExceptionHandler"));
}
defaultUncaughtExceptionHandler = ueh;
}
/**
* Returns the default handler invoked when a thread abruptly terminates
* due to an uncaught exception. If the returned value is {@code null},
* there is no default.
* @since 1.5
* @see #setDefaultUncaughtExceptionHandler
* @return the default uncaught exception handler for all threads
*/
public static UncaughtExceptionHandler getDefaultUncaughtExceptionHandler(){
return defaultUncaughtExceptionHandler;
}
/**
* Returns the handler invoked when this thread abruptly terminates
* due to an uncaught exception. If this thread has not had an
* uncaught exception handler explicitly set then this thread's
* {@code ThreadGroup} object is returned, unless this thread
* has terminated, in which case {@code null} is returned.
* @since 1.5
* @return the uncaught exception handler for this thread
*/
public UncaughtExceptionHandler getUncaughtExceptionHandler() {
if (isTerminated()) {
// uncaughtExceptionHandler may be set to null after thread terminates
return null;
} else {
UncaughtExceptionHandler ueh = uncaughtExceptionHandler;
return (ueh != null) ? ueh : getThreadGroup();
}
}
/**
* Set the handler invoked when this thread abruptly terminates
* due to an uncaught exception.
* <p>A thread can take full control of how it responds to uncaught
* exceptions by having its uncaught exception handler explicitly set.
* If no such handler is set then the thread's {@code ThreadGroup}
* object acts as its handler.
* @param ueh the object to use as this thread's uncaught exception
* handler. If {@code null} then this thread has no explicit handler.
* @throws SecurityException if the current thread is not allowed to
* modify this thread.
* @see #setDefaultUncaughtExceptionHandler
* @see ThreadGroup#uncaughtException
* @since 1.5
*/
public void setUncaughtExceptionHandler(UncaughtExceptionHandler ueh) {
checkAccess();
uncaughtExceptionHandler(ueh);
}
void uncaughtExceptionHandler(UncaughtExceptionHandler ueh) {
uncaughtExceptionHandler = ueh;
}
/**
* Dispatch an uncaught exception to the handler. This method is
* called when a thread terminates with an exception.
*/
void dispatchUncaughtException(Throwable e) {
getUncaughtExceptionHandler().uncaughtException(this, e);
}
/**
* Holder class for constants.
*/
@SuppressWarnings("removal")
private static class Constants {
// Thread group for virtual threads.
static final ThreadGroup VTHREAD_GROUP;
// AccessControlContext that doesn't support any permissions.
@SuppressWarnings("removal")
static final AccessControlContext NO_PERMISSIONS_ACC;
// Placeholder TCCL when thread locals not supported
static final ClassLoader NOT_SUPPORTED_CLASSLOADER;
static {
var getThreadGroup = new PrivilegedAction<ThreadGroup>() {
@Override
public ThreadGroup run() {
ThreadGroup parent = Thread.currentCarrierThread().getThreadGroup();
for (ThreadGroup p; (p = parent.getParent()) != null; )
parent = p;
return parent;
}
};
@SuppressWarnings("removal")
ThreadGroup root = AccessController.doPrivileged(getThreadGroup);
VTHREAD_GROUP = new ThreadGroup(root, "VirtualThreads", MAX_PRIORITY, false);
NO_PERMISSIONS_ACC = new AccessControlContext(new ProtectionDomain[] {
new ProtectionDomain(null, null)
});
var createClassLoader = new PrivilegedAction<ClassLoader>() {
@Override
public ClassLoader run() {
return new ClassLoader(null) { };
}
};
@SuppressWarnings("removal")
ClassLoader loader = AccessController.doPrivileged(createClassLoader);
NOT_SUPPORTED_CLASSLOADER = loader;
}
}
/**
* Returns the special ThreadGroup for virtual threads.
*/
static ThreadGroup virtualThreadGroup() {
return Constants.VTHREAD_GROUP;
}
// The following three initially uninitialized fields are exclusively
// managed by class java.util.concurrent.ThreadLocalRandom. These
// fields are used to build the high-performance PRNGs in the
// concurrent code.
/** The current seed for a ThreadLocalRandom */
long threadLocalRandomSeed;
/** Probe hash value; nonzero if threadLocalRandomSeed initialized */
int threadLocalRandomProbe;
/** Secondary seed isolated from public ThreadLocalRandom sequence */
int threadLocalRandomSecondarySeed;
/** The thread container that this thread is in */
private volatile ThreadContainer container; // @Stable candidate?
ThreadContainer threadContainer() {
return container;
}
void setThreadContainer(ThreadContainer container) {
// assert this.container == null;
this.container = container;
}
/** The top of this stack of stackable scopes owned by this thread */
private volatile StackableScope headStackableScopes;
StackableScope headStackableScopes() {
return headStackableScopes;
}
static void setHeadStackableScope(StackableScope scope) {
currentThread().headStackableScopes = scope;
}
/* Some private helper methods */
private native void setPriority0(int newPriority);
private native void interrupt0();
private static native void clearInterruptEvent();
private native void setNativeName(String name);
// The address of the next thread identifier, see ThreadIdentifiers.
private static native long getNextThreadIdOffset();
}