/* * 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.
*/
/** * 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
*/ publicclassThreadimplements Runnable { /* Make sure registerNatives is the first thing <clinit> does. */ privatestaticnativevoid registerNatives(); static {
registerNatives();
}
/* Reserved for exclusive use by the JVM, maybe move to FieldHolder */ privatelong eetop;
// thread id privatefinallong tid;
// thread name privatevolatile String name;
// interrupt status (read/written by VM) volatileboolean interrupted;
// 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. privatestaticclass FieldHolder { final ThreadGroup group; final Runnable task; finallong stackSize; volatileint priority; volatileboolean daemon; volatileint threadStatus;
/* * 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. privatestaticfinal Object NEW_THREAD_BINDINGS = Thread.class;
/** * Search the stack for the most recent scoped-value bindings.
*/
@IntrinsicCandidate staticnative 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
*/ privatevolatile 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
*/ staticvoid blockedOn(Interruptible b) { Thread me = Thread.currentThread(); synchronized (me.interruptLock) {
me.nioBlocker = b;
}
}
/** * The minimum priority that a thread can have.
*/ publicstaticfinalint MIN_PRIORITY = 1;
/** * The default priority that is assigned to a thread.
*/ publicstaticfinalint NORM_PRIORITY = 5;
/** * The maximum priority that a thread can have.
*/ publicstaticfinalint 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 staticnativeThread currentCarrierThread();
/** * Returns the Thread object for the current thread. * @return the current thread
*/
@IntrinsicCandidate publicstaticnativeThread currentThread();
/** * Sets the Thread object to be returned by Thread.currentThread().
*/
@IntrinsicCandidate nativevoid setCurrentThread(Threadthread);
/** * 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.
*/ publicstaticvoid yield() { if (currentThread() instanceof VirtualThread vthread) {
vthread.tryYield();
} else {
yield0();
}
}
privatestaticnativevoid 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.
*/ publicstaticvoid sleep(long millis) throws InterruptedException { if (millis < 0) { thrownew IllegalArgumentException("timeout value is negative");
}
if (currentThread() instanceof VirtualThread vthread) { long nanos = MILLISECONDS.toNanos(millis);
vthread.sleepNanos(nanos); return;
}
/** * 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.
*/ publicstaticvoid sleep(long millis, int nanos) throws InterruptedException { if (millis < 0) { thrownew IllegalArgumentException("timeout value is negative");
}
if (nanos < 0 || nanos > 999999) { thrownew 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;
}
/** * 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
*/ publicstaticvoid 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 publicstaticvoid onSpinWait() {}
/** * Characteristic value signifying that the thread cannot set values for its * copy of {@link ThreadLocal thread-locals}. * See Thread initialization.
*/ staticfinalint 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.
*/ staticfinalint 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.
*/ privatestaticclass ThreadIdentifiers { privatestaticfinal Unsafe U; privatestaticfinallong NEXT_TID_OFFSET; static {
U = Unsafe.getUnsafe();
NEXT_TID_OFFSET = Thread.getNextThreadIdOffset();
} staticlong next() { return U.getAndAddLong(null, NEXT_TID_OFFSET, 1);
}
}
/** * Returns the context class loader to inherit from the parent thread. * See Thread initialization.
*/ privatestatic 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) {
if (attached) { if (g == null) { thrownew 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());
}
// 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;
} elseif ((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;
}
} elseif (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;
} elseif ((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) publicstatic Builder.OfPlatform ofPlatform() { returnnew 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) publicstatic Builder.OfVirtual ofVirtual() {
PreviewFeatures.ensureEnabled(); returnnew 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);
/** * 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 {
/** * 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 {
/** * Throws CloneNotSupportedException as a Thread can not be meaningfully * cloned. Construct a new Thread instead. * * @throws CloneNotSupportedException * always
*/
@Override protected Object clone() throws CloneNotSupportedException { thrownew CloneNotSupportedException();
}
/** * Helper class for auto-numbering platform threads. The numbers start at * 0 and are separate from the thread identifier for historical reasons.
*/ privatestaticclass ThreadNumbering { privatestaticfinal Unsafe U; privatestaticfinal Object NEXT_BASE; privatestaticfinallong 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) { thrownew ExceptionInInitializerError(e);
}
} privatestaticvolatileint next; staticint 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.
*/ privatestatic String checkName(String name) { if (name == null) thrownew 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>
*/ publicThread() { 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>
*/ publicThread(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>
*/ publicThread(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>
*/ publicThread(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>
*/ publicThread(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>
*/ publicThread(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>
*/ publicThread(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>
*/ publicThread(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>
*/ publicThread(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) publicstaticThread startVirtualThread(Runnable task) {
Objects.requireNonNull(task);
PreviewFeatures.ensureEnabled(); varthread = ThreadBuilders.newVirtualThread(null, null, 0, task); thread.start(); returnthread;
}
/** * 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) publicfinalboolean isVirtual() { return (thisinstanceof 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
*/ publicvoid start() { synchronized (this) { // zero status corresponds to state "NEW". if (holder.threadStatus != 0) thrownew 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) thrownew 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);
}
}
}
}
privatenativevoid 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 publicvoid 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 privatevoid 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.
*/ privatevoid 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);
}
/** * 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) publicfinalvoid stop() { thrownew 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
*/ publicvoid 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
*/ publicstaticboolean 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
*/ publicboolean isInterrupted() { return interrupted;
}
finalvoid setInterrupt() { // assert Thread.currentCarrierThread() == this; if (!interrupted) {
interrupted = true;
interrupt0(); // inform VM of interrupt
}
}
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.
*/ publicfinalboolean isAlive() { return alive();
}
/** * Returns true if this thread is alive. * This method is non-final so it can be overridden.
*/ boolean alive() { return isAlive0();
} privatenativeboolean 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) publicfinalvoid suspend() { thrownew 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) publicfinalvoid resume() { thrownew 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()
*/ publicfinalvoid setPriority(int newPriority) {
checkAccess(); if (newPriority > MAX_PRIORITY || newPriority < MIN_PRIORITY) { thrownew 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
*/ publicfinalint getPriority() { if (isVirtual()) { returnThread.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()
*/ publicfinalsynchronizedvoid setName(String name) {
checkAccess(); if (name == null) { thrownew NullPointerException("name cannot be null");
} this.name = name; if (!isVirtual() && Thread.currentThread() == this) {
setNativeName(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}
*/ publicfinal ThreadGroup getThreadGroup() { if (isTerminated()) { returnnull;
} 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
*/ publicstaticint 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
*/ publicstaticint 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) publicint countStackFrames() { thrownew 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.
*/ publicfinalvoid join(long millis) throws InterruptedException { if (millis < 0) thrownew IllegalArgumentException("timeout value is negative");
if (thisinstanceof VirtualThread vthread) { if (isAlive()) { long nanos = MILLISECONDS.toNanos(millis);
vthread.joinNanos(nanos);
} return;
}
synchronized (this) { if (millis > 0) { if (isAlive()) { finallong 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.
*/ publicfinalvoid join(long millis, int nanos) throws InterruptedException { if (millis < 0) { thrownew IllegalArgumentException("timeout value is negative");
}
if (nanos < 0 || nanos > 999999) { thrownew IllegalArgumentException("nanosecond timeout value out of range");
}
if (thisinstanceof 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;
}
/** * 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.
*/ publicfinalvoid 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
*/ publicfinalboolean join(Duration duration) throws InterruptedException { long nanos = NANOSECONDS.convert(duration); // MAX_VALUE if > 292 years
Thread.State state = threadState(); if (state == State.NEW) thrownew IllegalThreadStateException("Thread not started"); if (state == State.TERMINATED) returntrue; if (nanos <= 0) returnfalse;
if (thisinstanceof 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.
*/ publicstaticvoid 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
*/ publicfinalvoid setDaemon(boolean on) {
checkAccess(); if (isVirtual() && !on) thrownew IllegalArgumentException("'false' not legal for virtual threads"); if (isAlive()) thrownew 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)
*/ publicfinalboolean isDaemon() { if (isVirtual()) { returntrue;
} 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) publicfinalvoid 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) returnnull; 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
*/ publicvoid setContextClassLoader(ClassLoader cl) {
@SuppressWarnings("removal")
SecurityManager sm = System.getSecurityManager(); if (sm != null) {
sm.checkPermission(new RuntimePermission("setContextClassLoader"));
} if (!isSupportedClassLoader(contextClassLoader)) { thrownew 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.
*/ privatestaticboolean isSupportedClassLoader(ClassLoader loader) { if (loader == null) returntrue; if (loader == jdk.internal.loader.ClassLoaders.appClassLoader()) returntrue; 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
*/ publicstaticnativeboolean holdsLock(Object obj);
privatestaticfinal 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) { returnnull;
}
StackTraceElement[] stes = (StackTraceElement[]) stackTrace; if (stes.length == 0) { returnnull;
} else { return StackTraceElement.of(stes);
}
}
privatenative 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
*/ publicstatic 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++) { Threadthread = 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;
}
/** * 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.
*/ privatestaticboolean isCCLOverridden(Class<?> cl) { if (cl == Thread.class) returnfalse;
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.
*/ privatestaticboolean auditSubclass(finalClass<?> subcl) {
@SuppressWarnings("removal") Boolean result = AccessController.doPrivileged( new PrivilegedAction<>() { publicBoolean run() { for (Class<?> cl = subcl;
cl != Thread.class;
cl = cl.getSuperclass())
{ try {
cl.getDeclaredMethod("getContextClassLoader", newClass<?>[0]); returnBoolean.TRUE;
} catch (NoSuchMethodException ex) {
} try { Class<?>[] params = {ClassLoader.class};
cl.getDeclaredMethod("setContextClassLoader", params); returnBoolean.TRUE;
} catch (NoSuchMethodException ex) {
}
} returnBoolean.FALSE;
}
}
); return result.booleanValue();
}
/** * Return an array of all live threads.
*/ staticThread[] 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);
}
/** * 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") publiclong 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
*/ publicfinallong 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
*/ publicenum 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 publicinterface 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 privatevolatile UncaughtExceptionHandler uncaughtExceptionHandler;
// null unless explicitly set privatestaticvolatile 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 "default" 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
*/ publicstaticvoid 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
*/ publicstatic 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 returnnull;
} 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
*/ publicvoid setUncaughtExceptionHandler(UncaughtExceptionHandler ueh) {
checkAccess();
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") privatestaticclass Constants { // Thread group for virtual threads. staticfinal ThreadGroup VTHREAD_GROUP;
// AccessControlContext that doesn't support any permissions.
@SuppressWarnings("removal") staticfinal AccessControlContext NO_PERMISSIONS_ACC;
// Placeholder TCCL when thread locals not supported staticfinal 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() { returnnew 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 */ privatevolatile 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 */ privatevolatile StackableScope headStackableScopes;
StackableScope headStackableScopes() { return headStackableScopes;
} staticvoid setHeadStackableScope(StackableScope scope) {
currentThread().headStackableScopes = scope;
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.