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