< prev index next >

src/java.base/share/classes/java/lang/Thread.java

Print this page
*** 28,240 ***
  import java.lang.ref.Reference;
  import java.lang.ref.ReferenceQueue;
  import java.lang.ref.WeakReference;
  import java.security.AccessController;
  import java.security.AccessControlContext;
  import java.security.PrivilegedAction;
  import java.util.Map;
  import java.util.HashMap;
  import java.util.concurrent.ConcurrentHashMap;
  import java.util.concurrent.ConcurrentMap;
  import java.util.concurrent.TimeUnit;
  import java.util.concurrent.locks.LockSupport;
  
  import jdk.internal.misc.TerminatingThreadLocal;
  import jdk.internal.reflect.CallerSensitive;
  import jdk.internal.reflect.Reflection;
  import jdk.internal.vm.annotation.IntrinsicCandidate;
  import sun.nio.ch.Interruptible;
  import sun.security.util.SecurityConstants;
  
  /**
   * 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>
-  * Every thread has a priority. Threads with higher priority are
-  * executed in preference to threads with lower priority. Each thread
-  * may or may not also be marked as a daemon. When code running in
-  * some thread creates a new {@code Thread} object, the new
-  * thread has its priority initially set equal to the priority of the
-  * creating thread, and is a daemon thread if and only if the
-  * creating thread is a daemon.
-  * <p>
-  * When a Java Virtual Machine starts up, there is usually a single
-  * non-daemon thread (which typically calls the method named
-  * {@code main} of some designated class). The Java Virtual
-  * Machine continues to execute threads until either of the following
-  * occurs:
-  * <ul>
-  * <li>The {@code exit} method of class {@code Runtime} has been
-  *     called and the security manager has permitted the exit operation
-  *     to take place.
-  * <li>All threads that are not daemon threads have died, either by
-  *     returning from the call to the {@code run} method or by
-  *     throwing an exception that propagates beyond the {@code run}
-  *     method.
-  * </ul>
-  * <p>
-  * There are two ways to create a new thread of execution. One is to
-  * declare a class to be a subclass of {@code Thread}. This
-  * subclass should override the {@code run} method of class
-  * {@code Thread}. An instance of the subclass can then be
-  * allocated and started. For example, a thread that computes primes
-  * larger than a stated value could be written as follows:
-  * <hr><blockquote><pre>
-  *     class PrimeThread extends Thread {
-  *         long minPrime;
-  *         PrimeThread(long minPrime) {
-  *             this.minPrime = minPrime;
-  *         }
   *
!  *         public void run() {
!  *             // compute primes larger than minPrime
!  *             &nbsp;.&nbsp;.&nbsp;.
!  *         }
!  *     }
!  * </pre></blockquote><hr>
!  * <p>
!  * The following code would then create a thread and start it running:
!  * <blockquote><pre>
!  *     PrimeThread p = new PrimeThread(143);
!  *     p.start();
!  * </pre></blockquote>
!  * <p>
!  * The other way to create a thread is to declare a class that
!  * implements the {@code Runnable} interface. That class then
!  * implements the {@code run} method. An instance of the class can
!  * then be allocated, passed as an argument when creating
!  * {@code Thread}, and started. The same example in this other
!  * style looks like the following:
!  * <hr><blockquote><pre>
!  *     class PrimeRun implements Runnable {
!  *         long minPrime;
!  *         PrimeRun(long minPrime) {
!  *             this.minPrime = minPrime;
!  *         }
   *
!  *         public void run() {
!  *             // compute primes larger than minPrime
!  *             &nbsp;.&nbsp;.&nbsp;.
!  *         }
!  *     }
!  * </pre></blockquote><hr>
!  * <p>
!  * The following code would then create a thread and start it running:
!  * <blockquote><pre>
!  *     PrimeRun p = new PrimeRun(143);
!  *     new Thread(p).start();
!  * </pre></blockquote>
!  * <p>
!  * Every thread has a name for identification purposes. More than
!  * one thread may have the same name. If a name is not specified when
!  * a thread is created, a new name is generated for it.
!  * <p>
!  * Unless otherwise noted, passing a {@code null} argument to a constructor
!  * or method in this class will cause a {@link NullPointerException} to be
!  * thrown.
   *
-  * @see     Runnable
-  * @see     Runtime#exit(int)
-  * @see     #run()
-  * @see     #stop()
   * @since   1.0
   */
  public class Thread implements Runnable {
      /* Make sure registerNatives is the first thing <clinit> does. */
      private static native void registerNatives();
      static {
          registerNatives();
      }
  
!     private volatile String name;
!     private int priority;
- 
-     /* Whether or not the thread is a daemon thread. */
-     private boolean daemon = false;
  
!     /* Interrupt state of the thread - read/written directly by JVM */
!     private volatile boolean interrupted;
  
!     /* Fields reserved for exclusive use by the JVM */
!     private boolean stillborn = false;
-     private long eetop;
  
!     /* What will be run. */
!     private Runnable target;
  
!     /* The group of this thread */
!     private ThreadGroup group;
  
!     /* The context ClassLoader for this thread */
!     private ClassLoader contextClassLoader;
  
!     /* The inherited AccessControlContext of this thread */
      @SuppressWarnings("removal")
      private AccessControlContext inheritedAccessControlContext;
  
!     /* For autonumbering anonymous threads. */
!     private static int threadInitNumber;
!     private static synchronized int nextThreadNum() {
!         return threadInitNumber++;
      }
  
      /* ThreadLocal values pertaining to this thread. This map is maintained
       * by the ThreadLocal class. */
!     ThreadLocal.ThreadLocalMap threadLocals = null;
  
      /*
       * InheritableThreadLocal values pertaining to this thread. This map is
       * maintained by the InheritableThreadLocal class.
       */
!     ThreadLocal.ThreadLocalMap inheritableThreadLocals = null;
  
!     /*
!      * The requested stack size for this thread, or 0 if the creator did
!      * not specify a stack size.  It is up to the VM to do whatever it
-      * likes with this number; some VMs will ignore it.
-      */
-     private final long stackSize;
  
!     /*
-      * Thread ID
-      */
-     private final long tid;
  
!     /* For generating thread ID */
!     private static long threadSeqNumber;
! 
!     private static synchronized long nextThreadID() {
!         return ++threadSeqNumber;
      }
  
      /*
!      * Java thread status for tools, default indicates thread 'not yet started'
       */
!     private volatile int threadStatus;
  
      /**
       * 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
       */
!     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.
       */
!     private volatile Interruptible blocker;
-     private final Object blockerLock = new Object();
  
      /* 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.blockerLock) {
!             me.blocker = 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;
  
      /**
!      * Returns a reference to the currently executing thread object.
!      *
!      * @return  the currently executing thread.
       */
      @IntrinsicCandidate
      public static native Thread currentThread();
  
      /**
       * 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.
       *
--- 28,349 ---
  import java.lang.ref.Reference;
  import java.lang.ref.ReferenceQueue;
  import java.lang.ref.WeakReference;
  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.concurrent.ConcurrentHashMap;
  import java.util.concurrent.ConcurrentMap;
+ import java.util.concurrent.ThreadFactory;
  import java.util.concurrent.TimeUnit;
  import java.util.concurrent.locks.LockSupport;
  
+ import jdk.internal.event.ThreadSleepEvent;
+ import jdk.internal.javac.PreviewFeature;
  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.ThreadContainer;
  import jdk.internal.vm.annotation.IntrinsicCandidate;
+ import jdk.internal.vm.annotation.Stable;
  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} provides a {@link Builder} and other APIs to create and
!  * start threads that execute {@link Runnable} tasks. Starting a thread schedules
!  * it to execute concurrently with the thread that caused it start. The newly
!  * started thread invokes the task's {@link Runnable#run() run} method. Thread
!  * defines the {@link #join() join} method to wait for a thread to terminate.
!  *
!  * <p> Threads have a unique {@linkplain #getId() 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 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 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 Java virtual machine terminates when all started non-daemon threads have
+  * terminated. Unstarted daemon threads do not prevent the Java virtual machine from
+  * terminating. The Java virtual machine can also be terminated by invoking the
+  * {@linkplain Runtime#exit(int)} method, in which case it will terminate even
+  * if there are non-daemon threads still running.
+  *
+  * <p> In addition to the daemon status, platform threads have a {@linkplain
+  * #getPriority() thread priority} and are members of a {@linkplain ThreadGroup
+  * thread group}.
+  *
+  * <p> Platform threads get an automatically generated thread name by default.
+  *
+  * <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
+  * virtual machine 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 the <i>scheduling
+  * points</i> where a carrier thread is re-scheduled from one virtual thread to
+  * another. Code executing in a virtual thread will usually not be aware of the
+  * underlying carrier thread, and in particular, the {@linkplain Thread#currentThread()}
+  * method, to obtain a reference to the <i>current thread</i>, will return the {@code
+  * Thread} object for the virtual thread, not the underlying carrier thread.
+  *
+  * <p> Virtual threads gets a fixed name by default.
+  *
+  * <h2>Creating and starting threads</h2>
+  *
+  * <p> As noted above, {@code Thread} defines a {@link Builder} API for creating and
+  * starting threads. The {@link #ofPlatform()} and {@link #ofVirtual()} methods are
+  * used to create builders for platform and virtual threads respectively.
+  * The following are examples that use the builder:
+  * <pre>{@code
+  *   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();
!  * }</pre>
!  *
!  * <p> In addition to the builder, {@code Thread} defines (for historical and
!  * customization reasons) public constructors for creating platform threads. Most
!  * applications should have little need to use these constructors directly or
!  * extend {@code Thread}. The constructors cannot be used to create virtual threads.
!  *
!  * <h2><a id="inheritance">Inheritance</a></h2>
!  * Creating a {@code Thread} will inherit, by default, the initial values of
!  * {@linkplain InheritableThreadLocal inheritable-thread-local} variables.
!  * Platform threads also inherit the daemon status, priority, and thread-group.
!  *
+  * <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.
   *
   * @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, TBD: move to FieldHolder */
!     private long eetop;
  
!     // holds fields for platform threads
!     private static class FieldHolder {
+         final ThreadGroup group;
+         final Runnable task;
+         final long stackSize;
+         int priority;
+         boolean daemon;
+         volatile int threadStatus;
+         boolean stillborn;
+ 
+         FieldHolder(ThreadGroup group,
+                     Runnable task,
+                     long stackSize,
+                     int priority,
+                     boolean daemon) {
+             this.group = group;
+             this.task = task;
+             this.stackSize = stackSize;
+             this.priority = priority;
+             this.daemon = daemon;
+         }
+     }
+     private final FieldHolder holder;
  
!     // interrupt status (read/written by VM)
!     volatile boolean interrupted;
  
!     // thread name
!     private volatile String name;
  
!     // thread id
!     private final long tid;
  
!     // context ClassLoader
!     private volatile ClassLoader contextClassLoader;
  
!     // inherited AccessControlContext, TBD: move this to FieldHolder
      @SuppressWarnings("removal")
      private AccessControlContext inheritedAccessControlContext;
  
!     /* For auto-numbering anonymous threads. */
!     private static class ThreadNumbering {
!         private static final Unsafe U = Unsafe.getUnsafe();
!         private static final long NEXT_NUMBER =
+             U.objectFieldOffset(ThreadNumbering.class, "nextNumber");
+         private static volatile int nextNumber;
+         static int next() {
+             return U.getAndAddInt(ThreadNumbering.class, NEXT_NUMBER, 1);
+         }
+     }
+     static String nextThreadName() {
+         return "Thread-" + ThreadNumbering.next();
      }
  
      /* 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;
  
!     // A simple (not very) random string of bits to use when evicting
!     // cache entries from the scoped variable cache.
!     int victims = 0b1100_1001_0000_1111_1101_1010_1010_0010;
  
!     ScopeLocal.Snapshot scopeLocalBindings = ScopeLocal.EmptySnapshot.getInstance();
  
!     /**
!      * Helper class to generate unique thread identifiers. The identifiers start
!      * at 2 as this class cannot be used during early startup to generate the
!      * identifier for the primordial thread.
!      */
+     private static class ThreadIdentifiers {
+         private static final Unsafe U = Unsafe.getUnsafe();
+         private static final long NEXT_TID_OFFSET =
+             U.objectFieldOffset(ThreadIdentifiers.class, "nextTid");
+         private static final long TID_MASK = (1L << 48) - 1;
+         private static volatile long nextTid = 2;
+         static long next() {
+             return U.getAndAddLong(ThreadIdentifiers.class, NEXT_TID_OFFSET, 1);
+         }
      }
  
      /*
!      * 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 platform 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 platform thread can have.
       */
      public static final int MAX_PRIORITY = 10;
  
      /**
!      * Characteristic value signifying that the thread cannot set values for its
!      * copy of {@link ThreadLocal thread-locals}
!      */
+     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.
+      */
+     static final int NO_INHERIT_THREAD_LOCALS = 1 << 2;
+ 
+     // 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;
+     }
+ 
+     /**
+      * Sets the Thread object to be returned by Thread.currentThread().
+      */
+     @IntrinsicCandidate
+     native void setCurrentThread(Thread thread);
+ 
+     /**
+      * Returns the Thread object for the current thread.
+      * @return  the current thread
       */
      @IntrinsicCandidate
      public static native Thread currentThread();
  
+     /**
+      * Returns the current carrier thread.
+      */
+     static Thread currentCarrierThread() {
+         return currentThread0();
+     }
+ 
+     @IntrinsicCandidate
+     private static native Thread currentThread0();
+ 
+     // ScopeLocal support:
+ 
+     /**
+      * TBD
+      * @return TBD
+      */
+     @IntrinsicCandidate
+     static native Object[] scopeLocalCache();
+ 
+     @IntrinsicCandidate
+     static native void setScopeLocalCache(Object[] cache);
+ 
      /**
       * 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.
       *

*** 274,11 ***
       * 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 native void yield();
  
      /**
       * 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
--- 383,19 ---
       * 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() {
+         Thread thread = currentThread();
+         if (thread 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

*** 293,11 ***
       * @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 native void sleep(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
--- 410,39 ---
       * @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 (ThreadSleepEvent.isTurnedOn()) {
+             ThreadSleepEvent event = new ThreadSleepEvent();
+             try {
+                 event.time = NANOSECONDS.convert(millis, MILLISECONDS);
+                 event.begin();
+                 sleepMillis(millis);
+             } finally {
+                 event.commit();
+             }
+         } else {
+             sleepMillis(millis);
+         }
+     }
+ 
+     private static void sleepMillis(long millis) throws InterruptedException {
+         Thread thread = currentThread();
+         if (thread instanceof VirtualThread vthread) {
+             long nanos = NANOSECONDS.convert(millis, MILLISECONDS);
+             vthread.sleepNanos(nanos);
+         } 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

*** 317,28 ***
       * @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 (nanos > 0 && millis < Long.MAX_VALUE) {
              millis++;
          }
  
          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.
--- 462,73 ---
       * @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 (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 less than zero.
+      *
+      * @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.
+      * @throws  NullPointerException
+      *          if duration is null
+      *
+      * @since 99
+      */
+     public static void sleep(Duration duration) throws InterruptedException {
+         long nanos = NANOSECONDS.convert(duration);  // MAX_VALUE if > 292 years
+         if (nanos < 0)
+             return;
+ 
+         Thread thread = currentThread();
+         if (thread instanceof VirtualThread vthread) {
+             if (ThreadSleepEvent.isTurnedOn()) {
+                 ThreadSleepEvent event = new ThreadSleepEvent();
+                 try {
+                     event.time = nanos;
+                     event.begin();
+                     vthread.sleepNanos(nanos);
+                 } finally {
+                     event.commit();
+                 }
+             } else {
+                 vthread.sleepNanos(nanos);
+             }
+         } else {
+             // convert to milliseconds, ceiling rounding mode
+             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.

*** 375,33 ***
       */
      @IntrinsicCandidate
      public static void onSpinWait() {}
  
      /**
!      * Initializes a Thread.
       *
       * @param g the Thread group
-      * @param target the object whose run() method gets called
       * @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 acc the AccessControlContext to inherit, or
       *            AccessController.getContext() if null
-      * @param inheritThreadLocals if {@code true}, inherit initial values for
-      *            inheritable thread-locals from the constructing thread
       */
      @SuppressWarnings("removal")
!     private Thread(ThreadGroup g, Runnable target, String name,
!                    long stackSize, AccessControlContext acc,
-                    boolean inheritThreadLocals) {
          if (name == null) {
              throw new NullPointerException("name cannot be null");
          }
  
-         this.name = name;
- 
          Thread parent = currentThread();
          SecurityManager security = System.getSecurityManager();
          if (g == null) {
              /* Determine if it's an applet or not */
  
              /* If there is a security manager, ask the security manager
--- 565,45 ---
       */
      @IntrinsicCandidate
      public static void onSpinWait() {}
  
      /**
!      * Returns the context class loader to inherit from the given parent thread
+      */
+     private static ClassLoader contextClassLoader(Thread parent) {
+         @SuppressWarnings("removal")
+         SecurityManager sm = System.getSecurityManager();
+         if (sm == null || isCCLOverridden(parent.getClass())) {
+             return parent.getContextClassLoader();
+         } else {
+             return parent.contextClassLoader;
+         }
+     }
+ 
+     /**
+      * Initializes a platform Thread.
       *
       * @param g the Thread group
       * @param name the name of the new Thread
+      * @param characteristics thread characteristics
+      * @param task the object whose run() method gets called
+ 
       * @param stackSize the desired stack size for the new thread, or
       *        zero to indicate that this parameter is to be ignored.
       * @param acc the AccessControlContext to inherit, or
       *            AccessController.getContext() if null
       */
      @SuppressWarnings("removal")
!     Thread(ThreadGroup g, String name, int characteristics, Runnable task,
!            long stackSize, AccessControlContext acc) {
          if (name == null) {
              throw new NullPointerException("name cannot be null");
          }
  
          Thread parent = currentThread();
+         boolean attached = (parent == this);
+ 
          SecurityManager security = System.getSecurityManager();
          if (g == null) {
              /* Determine if it's an applet or not */
  
              /* If there is a security manager, ask the security manager

*** 411,11 ***
              }
  
              /* If the security manager doesn't have a strong opinion
                 on the matter, use the parent thread group. */
              if (g == null) {
!                 g = parent.getThreadGroup();
              }
          }
  
          /*
           * Do we have the required permissions?
--- 613,12 ---
              }
  
              /* If the security manager doesn't have a strong opinion
                 on the matter, use the parent thread group. */
              if (g == null) {
!                 // avoid parent.getThreadGroup() during early startup
+                 g = getCurrentThreadGroup();
              }
          }
  
          /*
           * Do we have the required permissions?

*** 429,31 ***
                  security.checkPermission(
                          SecurityConstants.SUBCLASS_IMPLEMENTATION_PERMISSION);
              }
          }
  
!         g.addUnstarted();
  
!         this.group = g;
!         this.daemon = parent.isDaemon();
!         this.priority = parent.getPriority();
!         if (security == null || isCCLOverridden(parent.getClass()))
!             this.contextClassLoader = parent.getContextClassLoader();
!         else
!             this.contextClassLoader = parent.contextClassLoader;
!         this.inheritedAccessControlContext =
!                 acc != null ? acc : AccessController.getContext();
!         this.target = target;
!         setPriority(priority);
!         if (inheritThreadLocals && parent.inheritableThreadLocals != null)
-             this.inheritableThreadLocals =
-                 ThreadLocal.createInheritedMap(parent.inheritableThreadLocals);
-         /* Stash the specified stack size in case the VM cares */
-         this.stackSize = stackSize;
  
!         /* Set thread ID */
!         this.tid = nextThreadID();
      }
  
      /**
       * Throws CloneNotSupportedException as a Thread can not be meaningfully
       * cloned. Construct a new Thread instead.
--- 632,382 ---
                  security.checkPermission(
                          SecurityConstants.SUBCLASS_IMPLEMENTATION_PERMISSION);
              }
          }
  
!         this.name = name;
+         if (attached && VM.initLevel() < 1) {
+             this.tid = 1;  // primordial thread
+         } else {
+             this.tid = ThreadIdentifiers.next();
+         }
+         this.inheritedAccessControlContext = (acc != null) ? acc : AccessController.getContext();
+ 
+         // thread locals and scoped variables
+         if (!attached) {
+             if ((characteristics & NO_THREAD_LOCALS) != 0) {
+                 this.threadLocals = ThreadLocal.ThreadLocalMap.NOT_SUPPORTED;
+                 this.inheritableThreadLocals = ThreadLocal.ThreadLocalMap.NOT_SUPPORTED;
+                 this.contextClassLoader = ClassLoaders.NOT_SUPPORTED;
+             } 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 (parentLoader != ClassLoaders.NOT_SUPPORTED) {
+                     this.contextClassLoader = parentLoader;
+                 } else if (VM.isBooted()) {
+                     // parent does not support thread locals so no CCL to inherit
+                     this.contextClassLoader = ClassLoader.getSystemClassLoader();
+                 }
+             } else if (VM.isBooted()) {
+                 // default CCL to the system class loader when not inheriting
+                 this.contextClassLoader = ClassLoader.getSystemClassLoader();
+             }
+         }
  
!         int priority;
!         boolean daemon;
!         if (attached) {
!             // primordial or attached thread
!             priority = NORM_PRIORITY;
!             daemon = false;
!         } else {
!             priority = Math.min(parent.getPriority(), g.getMaxPriority());
!             daemon = parent.isDaemon();
!         }
!         this.holder = new FieldHolder(g, task, stackSize, priority, daemon);
!     }
  
!     /**
!      * Initializes a virtual Thread.
+      *
+      * @param name thread name, can be null
+      * @param characteristics thread characteristics
+      */
+     Thread(String name, int characteristics) {
+         Thread parent = currentThread();
+ 
+         this.name = (name != null) ? name : "<unnamed>";
+         this.tid = ThreadIdentifiers.next();
+         this.inheritedAccessControlContext = VirtualThreads.ACCESS_CONTROL_CONTEXT;
+ 
+         // thread locals
+         if ((characteristics & NO_THREAD_LOCALS) != 0) {
+             this.threadLocals = ThreadLocal.ThreadLocalMap.NOT_SUPPORTED;
+             this.inheritableThreadLocals = ThreadLocal.ThreadLocalMap.NOT_SUPPORTED;
+             this.contextClassLoader = ClassLoaders.NOT_SUPPORTED;
+         } 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 (parentLoader != ClassLoaders.NOT_SUPPORTED) {
+                 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();
+         }
+ 
+         // no additional fields
+         this.holder = null;
+     }
+ 
+     /**
+      * Returns a builder for creating a platform {@code Thread} or {@code ThreadFactory}
+      * that creates platform threads.
+      *
+      * @apiNote The following are examples using the builder:
+      * <pre>{@code
+      *   // 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();
+      * }</pre>
+      *
+      * @return A builder for creating {@code Thread} or {@code ThreadFactory} objects.
+      * @since 99
+      */
+     @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:
+      * <pre>{@code
+      *   // 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();
+      * }</pre>
+      *
+      * @return A builder for creating {@code Thread} or {@code ThreadFactory} objects.
+      * @since 99
+      */
+     @PreviewFeature(feature = PreviewFeature.Feature.VIRTUAL_THREADS)
+     public static Builder.OfVirtual ofVirtual() {
+         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 99
+      */
+     @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
+          * <pre>{@code
+          *   Thread.Builder builder = Thread.ofPlatform().name("worker-", 0);
+          *   Thread t1 = builder.start(task1);   // name "worker-0"
+          *   Thread t2 = builder.start(task2);   // name "worker-1"
+          * }</pre>
+          *
+          * @param prefix thread name prefix
+          * @param start the starting value of the counter
+          * @return this builder
+          * @throws IllegalArgumentException if count 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) set} method throws {@code
+          * UnsupportedOperationException} and the {@link ThreadLocal#get() get} method
+          * always returns the {@linkplain ThreadLocal#initialValue() initial-value}.
+          *
+          * @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 a thread group has been set and the current thread
+          *         cannot create a thread in that thread group
+          * @see <a href="Thread.html#inheritance">Inheritance</a>
+          */
+         Thread unstarted(Runnable task);
+ 
+         /**
+          * Creates a new {@code Thread} from the current state of the builder and
+          * schedules it to execute.
+          *
+          * @implSpec The default implementation invokes {@linkplain #unstarted(Runnable)
+          * unstarted} to create a {@code Thread} and then invokes its {@linkplain
+          * Thread#start() start} method to schedule it to execute.
+          *
+          * @param task the object to run when the thread executes
+          * @return a new started Thread
+          * @throws SecurityException if a thread group has been set and the current thread
+          *         cannot create a thread in that thread group
+          * @see <a href="Thread.html#inheritance">Inheritance</a>
+          */
+         default Thread start(Runnable task) {
+             Thread thread = unstarted(task);
+             thread.start();
+             return thread;
+         }
+ 
+         /**
+          * 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.
+          *
+          * @see Thread#ofPlatform()
+          * @since 99
+          */
+         @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> Virtual threads created with a builder, or with a {@code ThreadFactory}
+          * created from a builder, have no {@link Permission permissions}.
+          *
+          * @see Thread#ofVirtual()
+          * @since 99
+          */
+         @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.

*** 465,89 ***
      protected Object clone() throws CloneNotSupportedException {
          throw new CloneNotSupportedException();
      }
  
      /**
!      * Allocates a new {@code Thread} object. 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.
       */
      public Thread() {
!         this(null, null, "Thread-" + nextThreadNum(), 0);
      }
  
      /**
!      * Allocates a new {@code Thread} object. This constructor has the same
       * effect as {@linkplain #Thread(ThreadGroup,Runnable,String) Thread}
!      * {@code (null, target, 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.
       *
!      * @param  target
       *         the object whose {@code run} method is invoked when this thread
       *         is started. If {@code null}, this classes {@code run} method does
       *         nothing.
       */
!     public Thread(Runnable target) {
!         this(null, target, "Thread-" + nextThreadNum(), 0);
      }
  
      /**
       * Creates a new Thread that inherits the given AccessControlContext
       * but thread-local variables are not inherited.
       * This is not a public constructor.
       */
!     Thread(Runnable target, @SuppressWarnings("removal") AccessControlContext acc) {
!         this(null, target, "Thread-" + nextThreadNum(), 0, acc, false);
      }
  
      /**
!      * Allocates a new {@code Thread} object. This constructor has the same
       * effect as {@linkplain #Thread(ThreadGroup,Runnable,String) Thread}
!      * {@code (group, target, 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.
       *
       * @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  target
       *         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
       */
!     public Thread(ThreadGroup group, Runnable target) {
!         this(group, target, "Thread-" + nextThreadNum(), 0);
      }
  
      /**
!      * Allocates a new {@code Thread} object. This constructor has the same
       * effect as {@linkplain #Thread(ThreadGroup,Runnable,String) Thread}
       * {@code (null, null, name)}.
       *
       * @param   name
       *          the name of the new thread
       */
      public Thread(String name) {
          this(null, null, name, 0);
      }
  
      /**
!      * Allocates a new {@code Thread} object. This constructor has the same
       * effect as {@linkplain #Thread(ThreadGroup,Runnable,String) Thread}
       * {@code (group, null, name)}.
       *
       * @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
--- 1019,113 ---
      protected Object clone() throws CloneNotSupportedException {
          throw new CloneNotSupportedException();
      }
  
      /**
!      * Allocates 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</a>
       */
      public Thread() {
!         this(null, null, nextThreadName(), 0);
      }
  
      /**
!      * Allocates 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</a>
       */
!     public Thread(Runnable task) {
!         this(null, task, nextThreadName(), 0);
      }
  
      /**
       * 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, nextThreadName(), 0, task, 0, acc);
      }
  
      /**
!      * Allocates 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</a>
       */
!     public Thread(ThreadGroup group, Runnable task) {
!         this(group, task, nextThreadName(), 0);
      }
  
      /**
!      * Allocates 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</a>
       */
      public Thread(String name) {
          this(null, null, name, 0);
      }
  
      /**
!      * Allocates 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

*** 558,33 ***
       *         the name of the new thread
       *
       * @throws  SecurityException
       *          if the current thread cannot create a thread in the specified
       *          thread group
       */
      public Thread(ThreadGroup group, String name) {
          this(group, null, name, 0);
      }
  
      /**
!      * Allocates a new {@code Thread} object. This constructor has the same
       * effect as {@linkplain #Thread(ThreadGroup,Runnable,String) Thread}
!      * {@code (null, target, name)}.
       *
!      * @param  target
       *         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
       */
!     public Thread(Runnable target, String name) {
!         this(null, target, name, 0);
      }
  
      /**
!      * Allocates a new {@code Thread} object so that it has {@code target}
       * 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}
--- 1136,41 ---
       *         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</a>
       */
      public Thread(ThreadGroup group, String name) {
          this(group, null, name, 0);
      }
  
      /**
!      * Allocates 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</a>
       */
!     public Thread(Runnable task, String name) {
!         this(null, task, name, 0);
      }
  
      /**
!      * Allocates 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}

*** 594,45 ***
       * 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 set equal to the
!      * priority of the thread creating it, that is, the currently running
!      * thread. 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.
       *
       * @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  target
       *         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.
       */
!     public Thread(ThreadGroup group, Runnable target, String name) {
!         this(group, target, name, 0);
      }
  
      /**
!      * Allocates a new {@code Thread} object so that it has {@code target}
       * 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
--- 1180,51 ---
       * 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</a>
       */
!     public Thread(ThreadGroup group, Runnable task, String name) {
!         this(group, task, name, 0);
      }
  
      /**
!      * Allocates 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

*** 675,20 ***
       *
       * <p>Implementation note: Java platform implementers are encouraged to
       * document their implementation's behavior with respect to the
       * {@code stackSize} parameter.
       *
       *
       * @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  target
       *         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
--- 1267,23 ---
       *
       * <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

*** 700,18 ***
       * @throws  SecurityException
       *          if the current thread cannot create a thread in the specified
       *          thread group
       *
       * @since 1.4
       */
!     public Thread(ThreadGroup group, Runnable target, String name,
!                   long stackSize) {
-         this(group, target, name, stackSize, null, true);
      }
  
      /**
!      * Allocates a new {@code Thread} object so that it has {@code target}
       * 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}.
--- 1295,18 ---
       * @throws  SecurityException
       *          if the current thread cannot create a thread in the specified
       *          thread group
       *
       * @since 1.4
+      * @see <a href="#inheritance">Inheritance</a>
       */
!     public Thread(ThreadGroup group, Runnable task, String name, long stackSize) {
!         this(group, name, 0, task, stackSize, null);
      }
  
      /**
!      * Allocates 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}.

*** 727,90 ***
       *
       * <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.
       *
       * @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  target
       *         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  inheritThreadLocals
       *         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
       */
!     public Thread(ThreadGroup group, Runnable target, String name,
!                   long stackSize, boolean inheritThreadLocals) {
!         this(group, target, name, stackSize, null, inheritThreadLocals);
      }
  
      /**
!      * Causes this thread to begin execution; the Java Virtual Machine
!      * calls the {@code run} method of this thread.
!      * <p>
!      * The result is that two threads are running concurrently: the
!      * current thread (which returns from the call to the
!      * {@code start} method) and the other thread (which executes its
!      * {@code run} method).
       * <p>
       * It is never legal to start a thread more than once.
       * In particular, a thread may not be restarted once it has completed
       * execution.
       *
       * @throws     IllegalThreadStateException  if the thread was already started.
!      * @see        #run()
!      * @see        #stop()
!      */
!     public synchronized void start() {
!         /**
!          * This method is not invoked for the main method thread or "system"
!          * group threads created/set up by the VM. Any new functionality added
!          * to this method in the future may have to also be added to the VM.
!          *
!          * A zero status value corresponds to state "NEW".
!          */
-         if (threadStatus != 0)
-             throw new IllegalThreadStateException();
  
!         /* Notify the group that this thread is about to be started
!          * so that it can be added to the group's list of threads
!          * and the group's unstarted count can be decremented. */
!         group.add(this);
  
!         boolean started = false;
!         try {
-             start0();
-             started = true;
-         } finally {
              try {
                  if (!started) {
!                     group.threadStartFailed(this);
                  }
-             } catch (Throwable ignore) {
-                 /* do nothing. If start0 threw a Throwable then
-                   it will be passed up the call stack */
              }
          }
      }
  
      private native void start0();
--- 1322,143 ---
       *
       * <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</a>
       */
!     public Thread(ThreadGroup group, Runnable task, String name,
!                   long stackSize, boolean inheritInheritableThreadLocals) {
!         this(group, name,
+                 (inheritInheritableThreadLocals ? 0 : NO_INHERIT_THREAD_LOCALS),
+                 task, stackSize, null);
      }
  
      /**
!      * Creates a virtual thread to execute a task and schedules it to execute.
!      *
!      * <p> The thread has no {@link Permission permissions}.
!      *
!      * <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
+      * @see <a href="#inheritance">Inheritance</a>
+      * @since 99
+      */
+     @PreviewFeature(feature = PreviewFeature.Feature.VIRTUAL_THREADS)
+     public static Thread startVirtualThread(Runnable task) {
+         var thread = new VirtualThread(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 99
+      */
+     @PreviewFeature(feature = PreviewFeature.Feature.VIRTUAL_THREADS)
+     public final boolean isVirtual() {
+         return (this instanceof VirtualThread);
+     }
+ 
+     /**
+      * Schedules this thread to begin execution. The thread will execute
+      * independently of the current thread.
       * <p>
       * It is never legal to start a thread more than once.
       * In particular, a thread may not be restarted once it has completed
       * execution.
       *
       * @throws     IllegalThreadStateException  if the thread was already started.
!      * @throws     java.util.concurrent.RejectedExecutionException if the thread
!      *             is virtual and the scheduler cannot accept a task
!      */
!     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();
  
!             boolean started = false;
!             container.onStart(this);  // may throw
              try {
+                 // inherit scope locals from structured container
+                 Object bindings = container.scopeLocalBindings();
+                 if (bindings != null) {
+                     if (Thread.currentThread().scopeLocalBindings != bindings) {
+                         throw new IllegalStateException("Scope local bindings have changed");
+                     }
+                     this.scopeLocalBindings = (ScopeLocal.Snapshot) bindings;
+                 }
+ 
+                 // bind thread to container
+                 setThreadContainer(container);
+ 
+                 start0();
+                 started = true;
+             } finally {
                  if (!started) {
!                     container.onExit(this);
                  }
              }
          }
      }
  
      private native void start0();

*** 818,44 ***
      /**
       * If this thread was constructed using a separate
       * {@code Runnable} run object, then that
       * {@code Runnable} object's {@code run} method is called;
       * otherwise, this method does nothing and returns.
       * <p>
       * Subclasses of {@code Thread} should override this method.
       *
       * @see     #start()
-      * @see     #stop()
       * @see     #Thread(ThreadGroup, Runnable, String)
       */
      @Override
      public void run() {
!         if (target != null) {
!             target.run();
          }
      }
  
      /**
       * This method is called by the system to give a Thread
       * a chance to clean up before it actually exits.
       */
      private void exit() {
!         if (threadLocals != null && TerminatingThreadLocal.REGISTRY.isPresent()) {
!             TerminatingThreadLocal.threadTerminated();
          }
!         if (group != null) {
!             group.threadTerminated(this);
!             group = null;
          }
-         /* Aggressively null out all reference fields: see bug 4006245 */
-         target = null;
-         /* Speed the release of some of these resources */
-         threadLocals = null;
-         inheritableThreadLocals = null;
-         inheritedAccessControlContext = null;
-         blocker = null;
-         uncaughtExceptionHandler = null;
      }
  
      /**
       * Forces the thread to stop executing.
       * <p>
--- 1466,58 ---
      /**
       * If this thread was constructed using a separate
       * {@code Runnable} run object, then that
       * {@code Runnable} object's {@code run} method is called;
       * otherwise, this method does nothing and returns.
+      * This method does nothing when invoked on a {@linkplain #isVirtual()
+      * virtual} thread.
       * <p>
       * Subclasses of {@code Thread} should override this method.
       *
       * @see     #start()
       * @see     #Thread(ThreadGroup, Runnable, String)
       */
      @Override
      public void run() {
!         if (!isVirtual()) {
!             Runnable task = holder.task;
+             if (task != null) {
+                 task.run();
+             }
          }
      }
  
+     /**
+      * Null out reference after Thread termination (JDK-4006245)
+      */
+     void clearReferences() {
+         threadLocals = null;
+         inheritableThreadLocals = null;
+         inheritedAccessControlContext = null;
+         if (uncaughtExceptionHandler != null)
+             uncaughtExceptionHandler = null;
+         if (nioBlocker != null)
+             nioBlocker = null;
+     }
+ 
      /**
       * This method is called by the system to give a Thread
       * a chance to clean up before it actually exits.
       */
      private void exit() {
!         ThreadContainer container = threadContainer();
!         if (container != null) {
+             container.onExit(this);
          }
! 
!         try {
!             if (threadLocals != null && TerminatingThreadLocal.REGISTRY.isPresent()) {
+                 TerminatingThreadLocal.threadTerminated();
+             }
+         } finally {
+             clearReferences();
          }
      }
  
      /**
       * Forces the thread to stop executing.
       * <p>

*** 882,21 ***
       * An application should not normally try to catch
       * {@code ThreadDeath} unless it must do some extraordinary
       * cleanup operation (note that the throwing of
       * {@code ThreadDeath} causes {@code finally} clauses of
       * {@code try} statements to be executed before the thread
!      * officially dies).  If a {@code catch} clause catches a
       * {@code ThreadDeath} object, it is important to rethrow the
!      * object so that the thread actually dies.
       * <p>
       * The top-level error handler that reacts to otherwise uncaught
       * exceptions does not print out a message or otherwise notify the
       * application if the uncaught exception is an instance of
       * {@code ThreadDeath}.
       *
       * @throws     SecurityException  if the current thread cannot
       *             modify this thread.
       * @see        #interrupt()
       * @see        #checkAccess()
       * @see        #run()
       * @see        #start()
       * @see        ThreadDeath
--- 1544,22 ---
       * An application should not normally try to catch
       * {@code ThreadDeath} unless it must do some extraordinary
       * cleanup operation (note that the throwing of
       * {@code ThreadDeath} causes {@code finally} clauses of
       * {@code try} statements to be executed before the thread
!      * officially terminates).  If a {@code catch} clause catches a
       * {@code ThreadDeath} object, it is important to rethrow the
!      * object so that the thread actually terminates.
       * <p>
       * The top-level error handler that reacts to otherwise uncaught
       * exceptions does not print out a message or otherwise notify the
       * application if the uncaught exception is an instance of
       * {@code ThreadDeath}.
       *
       * @throws     SecurityException  if the current thread cannot
       *             modify this thread.
+      * @throws     UnsupportedOperationException if invoked on a virtual thread
       * @see        #interrupt()
       * @see        #checkAccess()
       * @see        #run()
       * @see        #start()
       * @see        ThreadDeath

*** 920,23 ***
       *       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")
      public final void stop() {
          @SuppressWarnings("removal")
          SecurityManager security = System.getSecurityManager();
          if (security != null) {
              checkAccess();
              if (this != Thread.currentThread()) {
                  security.checkPermission(SecurityConstants.STOP_THREAD_PERMISSION);
              }
          }
          // A zero status value corresponds to "NEW", it can't change to
          // not-NEW because we hold the lock.
!         if (threadStatus != 0) {
              resume(); // Wake up thread if it was suspended; no-op otherwise
          }
  
          // The VM can handle all thread states
          stop0(new ThreadDeath());
--- 1583,27 ---
       *       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() {
          @SuppressWarnings("removal")
          SecurityManager security = System.getSecurityManager();
          if (security != null) {
              checkAccess();
              if (this != Thread.currentThread()) {
                  security.checkPermission(SecurityConstants.STOP_THREAD_PERMISSION);
              }
          }
+ 
+         if (isVirtual())
+             throw new UnsupportedOperationException();
+ 
          // A zero status value corresponds to "NEW", it can't change to
          // not-NEW because we hold the lock.
!         if (holder.threadStatus != 0) {
              resume(); // Wake up thread if it was suspended; no-op otherwise
          }
  
          // The VM can handle all thread states
          stop0(new ThreadDeath());

*** 987,23 ***
      public void interrupt() {
          if (this != Thread.currentThread()) {
              checkAccess();
  
              // thread may be blocked in an I/O operation
!             synchronized (blockerLock) {
!                 Interruptible b = blocker;
                  if (b != null) {
                      interrupted = true;
                      interrupt0();  // inform VM of interrupt
                      b.interrupt(this);
                      return;
                  }
              }
          }
          interrupted = true;
!         // inform VM of interrupt
-         interrupt0();
      }
  
      /**
       * Tests whether the current thread has been interrupted.  The
       * <i>interrupted status</i> of the thread is cleared by this method.  In
--- 1654,22 ---
      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

*** 1016,20 ***
       *          {@code false} otherwise.
       * @see #isInterrupted()
       * @revised 6.0, 14
       */
      public static boolean interrupted() {
!         Thread t = currentThread();
-         boolean interrupted = t.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 (interrupted) {
-             t.interrupted = false;
-             clearInterruptEvent();
-         }
-         return interrupted;
      }
  
      /**
       * Tests whether this thread has been interrupted.  The <i>interrupted
       * status</i> of the thread is unaffected by this method.
--- 1682,11 ---
       *          {@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.

*** 1041,18 ***
       */
      public boolean isInterrupted() {
          return interrupted;
      }
  
      /**
       * Tests if this thread is alive. A thread is alive if it has
!      * been started and has not yet died.
       *
       * @return  {@code true} if this thread is alive;
       *          {@code false} otherwise.
       */
!     public final native boolean isAlive();
  
      /**
       * Suspends this thread.
       * <p>
       * First, the {@code checkAccess} method of this thread is called
--- 1698,54 ---
       */
      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() {
+         if (isVirtual()) {
+             State state = getState();
+             return (state != State.NEW && state != State.TERMINATED);
+         } else {
+             return isAlive0();
+         }
+     }
+     private native boolean isAlive0();
  
      /**
       * Suspends this thread.
       * <p>
       * First, the {@code checkAccess} method of this thread is called

*** 1062,10 ***
--- 1755,11 ---
       * If the thread is alive, it is suspended and makes no further
       * progress unless and until it is resumed.
       *
       * @throws     SecurityException  if the current thread cannot modify
       *             this thread.
+      * @throws     UnsupportedOperationException if invoked on a virtual thread
       * @see #checkAccess
       * @deprecated   This method has been deprecated, as it is
       *   inherently deadlock-prone.  If the target thread holds a lock on the
       *   monitor protecting a critical system resource when it is suspended, no
       *   thread can access this resource until the target thread is resumed. If

*** 1077,10 ***
--- 1771,12 ---
       *   are Thread.stop, Thread.suspend and Thread.resume Deprecated?</a>.
       */
      @Deprecated(since="1.2", forRemoval=true)
      public final void suspend() {
          checkAccess();
+         if (isVirtual())
+             throw new UnsupportedOperationException();
          suspend0();
      }
  
      /**
       * Resumes a suspended thread.

*** 1092,10 ***
--- 1788,11 ---
       * If the thread is alive but suspended, it is resumed and is
       * permitted to make progress in its execution.
       *
       * @throws     SecurityException  if the current thread cannot modify this
       *             thread.
+      * @throws     UnsupportedOperationException if invoked on a virtual thread
       * @see        #checkAccess
       * @see        #suspend()
       * @deprecated This method exists solely for use with {@link #suspend},
       *     which has been deprecated because it is deadlock-prone.
       *     For more information, see

*** 1103,67 ***
       *     are Thread.stop, Thread.suspend and Thread.resume Deprecated?</a>.
       */
      @Deprecated(since="1.2", forRemoval=true)
      public final void resume() {
          checkAccess();
          resume0();
      }
  
      /**
       * Changes the priority of this thread.
!      * <p>
!      * First the {@code checkAccess} method of this thread is called
!      * with no arguments. This may result in throwing a {@code SecurityException}.
!      * <p>
!      * Otherwise, the priority of this thread is set to the smaller of
!      * the specified {@code newPriority} and the maximum permitted
!      * priority of the thread's thread group.
!      *
!      * @param newPriority priority to set this thread to
!      * @throws     IllegalArgumentException  If the priority is not in the
!      *               range {@code MIN_PRIORITY} to
!      *               {@code MAX_PRIORITY}.
!      * @throws     SecurityException  if the current thread cannot modify
!      *               this thread.
!      * @see        #getPriority
!      * @see        #checkAccess()
-      * @see        #getThreadGroup()
-      * @see        #MAX_PRIORITY
-      * @see        #MIN_PRIORITY
-      * @see        ThreadGroup#getMaxPriority()
       */
      public final void setPriority(int newPriority) {
-         ThreadGroup g;
          checkAccess();
          if (newPriority > MAX_PRIORITY || newPriority < MIN_PRIORITY) {
              throw new IllegalArgumentException();
          }
!         if((g = getThreadGroup()) != null) {
!             if (newPriority > g.getMaxPriority()) {
!                 newPriority = g.getMaxPriority();
              }
!             setPriority0(priority = newPriority);
          }
      }
  
      /**
       * Returns this thread's priority.
       *
       * @return  this thread's priority.
       * @see     #setPriority
       */
      public final int getPriority() {
!         return 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}.
       *
       * @param      name   the new name for this thread.
       * @throws     SecurityException  if the current thread cannot modify this
       *             thread.
       * @see        #getName
       * @see        #checkAccess()
--- 1800,83 ---
       *     are Thread.stop, Thread.suspend and Thread.resume Deprecated?</a>.
       */
      @Deprecated(since="1.2", forRemoval=true)
      public final void resume() {
          checkAccess();
+         if (isVirtual())
+             throw new UnsupportedOperationException();
          resume0();
      }
  
      /**
       * 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.
+      * 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
+      * If this thread is the current thread, and is a platform thread that isn't
+      * mapped to a native thread attached to the VM with the Java Native Interface
+      * {@code AttachCurrentThread} function, then a best effort attempt is made to
+      * change the operating system thread name too.
+      *
       * @param      name   the new name for this thread.
       * @throws     SecurityException  if the current thread cannot modify this
       *             thread.
       * @see        #getName
       * @see        #checkAccess()

*** 1173,11 ***
          if (name == null) {
              throw new NullPointerException("name cannot be null");
          }
  
          this.name = name;
!         if (threadStatus != 0) {
              setNativeName(name);
          }
      }
  
      /**
--- 1886,11 ---
          if (name == null) {
              throw new NullPointerException("name cannot be null");
          }
  
          this.name = name;
!         if (!isVirtual() && Thread.currentThread() == this) {
              setNativeName(name);
          }
      }
  
      /**

*** 1190,44 ***
          return name;
      }
  
      /**
       * Returns the thread group to which this thread belongs.
!      * This method returns null if this thread has died
-      * (been stopped).
       *
       * @return  this thread's thread group.
       */
      public final ThreadGroup getThreadGroup() {
!         return group;
      }
  
      /**
       * Returns an estimate of the number of active threads in the current
       * thread's {@linkplain java.lang.ThreadGroup thread group} and its
!      * subgroups. Recursively iterates over all subgroups in the current
!      * thread's thread group.
       *
       * <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 active 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 active 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.
       *
       * <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 active
--- 1903,67 ---
          return name;
      }
  
      /**
       * Returns the thread group to which this thread belongs.
!      * This method returns null if the thread has terminated.
       *
       * @return  this thread's thread group.
       */
      public final ThreadGroup getThreadGroup() {
!         if (getState() == State.TERMINATED) {
+             return null;
+         } else {
+             return isVirtual() ? VirtualThreads.THREAD_GROUP : holder.group;
+         }
+     }
+ 
+     /**
+      * Returns the thread group for the current thread.
+      */
+     static ThreadGroup getCurrentThreadGroup() {
+         Thread thread = Thread.currentThread();
+         if (thread.isVirtual()) {
+             return VirtualThreads.THREAD_GROUP;
+         } else {
+             return thread.holder.group;
+         }
      }
  
      /**
       * Returns an estimate of the number of active threads in the current
       * thread's {@linkplain java.lang.ThreadGroup thread group} and its
!      * subgroups. Virtual threads are not considered active threads in a
!      * thread group so this method does not include virtual threads 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 active 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
+      *
+      * @deprecated This method is obsolete. Code that needs an estimate of the
+      *     number of active platform threads in a thread group can invoke the
+      *     thread group's {@link ThreadGroup#activeCount()} method.
       */
+     @Deprecated(since = "99")
      public static int activeCount() {
          return currentThread().getThreadGroup().activeCount();
      }
  
      /**
       * Copies into the specified array every active 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 considered active threads in a thread group so this method
+      * does not enumerate virtual threads.
       *
       * <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 active

*** 1244,11 ***
--- 1980,16 ---
       * @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
+      *
+      * @deprecated This method is obsolete. Code that needs to enumerate the
+      *     active platform threads can invoke the thread group's {@link
+      *     ThreadGroup#enumerate(Thread[])} method.
       */
+     @Deprecated(since = "99")
      public static int enumerate(Thread[] tarray) {
          return currentThread().getThreadGroup().enumerate(tarray);
      }
  
      /**

*** 1266,15 ***
      public int countStackFrames() {
          throw new UnsupportedOperationException();
      }
  
      /**
!      * Waits at most {@code millis} milliseconds for this thread to
!      * die. A timeout of {@code 0} means to wait forever.
       *
!      * <p> This 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
--- 2007,18 ---
      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

*** 1286,37 ***
       * @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 synchronized void join(final long millis)
!     throws InterruptedException {
!         if (millis > 0) {
              if (isAlive()) {
!                 final long startTime = System.nanoTime();
!                 long delay = millis;
-                 do {
-                     wait(delay);
-                 } while (isAlive() && (delay = millis -
-                         TimeUnit.NANOSECONDS.toMillis(System.nanoTime() - startTime)) > 0);
              }
!         } else if (millis == 0) {
!             while (isAlive()) {
!                 wait(0);
              }
-         } else {
-             throw new IllegalArgumentException("timeout value is negative");
          }
      }
  
      /**
       * Waits at most {@code millis} milliseconds plus
!      * {@code nanos} nanoseconds for this thread to die.
       * If both arguments are {@code 0}, it means to wait forever.
       *
!      * <p> This 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
--- 2030,50 ---
       * @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 -
+                             TimeUnit.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

*** 1332,31 ***
       * @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 synchronized 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 (nanos > 0 && millis < Long.MAX_VALUE) {
              millis++;
          }
  
          join(millis);
      }
  
      /**
!      * Waits for this thread to die.
       *
       * <p> An invocation of this method behaves in exactly the same
       * way as the invocation
       *
       * <blockquote>
--- 2089,28 ---
       * @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 (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>

*** 1370,52 ***
       */
      public final void join() throws InterruptedException {
          join(0);
      }
  
      /**
       * Prints a stack trace of the current thread to the standard error stream.
!      * This method is used only for debugging.
       */
      public static void dumpStack() {
          new Exception("Stack trace").printStackTrace();
      }
  
      /**
!      * Marks this thread as either a {@linkplain #isDaemon daemon} thread
!      * or a user thread. The Java Virtual Machine exits when the only
!      * threads running are all daemon threads.
       *
!      * <p> This method must be invoked before the thread is started.
       *
       * @param  on
       *         if {@code true}, marks this thread as a daemon thread
       *
       * @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 (isAlive()) {
              throw new IllegalThreadStateException();
!         }
!         daemon = on;
      }
  
      /**
       * Tests if this thread is a daemon thread.
       *
       * @return  {@code true} if this thread is a daemon thread;
       *          {@code false} otherwise.
       * @see     #setDaemon(boolean)
       */
      public final boolean isDaemon() {
!         return daemon;
      }
  
      /**
       * Determines if the currently running thread has permission to
       * modify this thread.
--- 2124,115 ---
       */
      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 99
+      */
+     public final boolean join(Duration duration) throws InterruptedException {
+         long nanos = NANOSECONDS.convert(duration); // MAX_VALUE if > 292 years
+ 
+         Thread.State state = getState();
+         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);
+         } else {
+             // convert to milliseconds, ceiling rounding mode
+             long millis = MILLISECONDS.convert(nanos, NANOSECONDS);
+             if (nanos > NANOSECONDS.convert(millis, MILLISECONDS)) {
+                 millis += 1L;
+             }
+             join(millis);
+             return getState() == State.TERMINATED;
+         }
+     }
+ 
      /**
       * 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 Java virtual machine terminates when all started non-daemon threads have
!      * terminated.
       *
!      * 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.

*** 1442,36 ***
              security.checkAccess(this);
          }
      }
  
      /**
!      * Returns a string representation of this thread, including the
!      * thread's name, priority, and thread group.
       *
       * @return  a string representation of this thread.
       */
      public String toString() {
          ThreadGroup group = getThreadGroup();
!         if (group != null) {
!             return "Thread[" + getName() + "," + getPriority() + "," +
!                            group.getName() + "]";
!         } else {
-             return "Thread[" + getName() + "," + getPriority() + "," +
-                             "" + "]";
-         }
      }
  
      /**
!      * Returns the context {@code ClassLoader} for this thread. The context
!      * {@code ClassLoader} is provided 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 the
!      * {@code ClassLoader} context of the parent thread. 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)
       *
--- 2259,41 ---
              security.checkAccess(this);
          }
      }
  
      /**
!      * Returns a string representation of this thread. The string representation
!      * will usually include the thread's 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(getId());
+         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)
       *

*** 1483,38 ***
       *
       * @since 1.2
       */
      @CallerSensitive
      public ClassLoader getContextClassLoader() {
!         if (contextClassLoader == null)
              return null;
          @SuppressWarnings("removal")
          SecurityManager sm = System.getSecurityManager();
          if (sm != null) {
!             ClassLoader.checkClassLoaderPermission(contextClassLoader,
!                                                    Reflection.getCallerClass());
          }
!         return contextClassLoader;
      }
  
      /**
!      * Sets the context ClassLoader for this Thread. The context
!      * ClassLoader can be set when a thread is created, and allows
!      * the creator of the thread to provide the appropriate class loader,
-      * through {@code getContextClassLoader}, to code running in the thread
-      * when loading classes and resources.
       *
!      * <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  SecurityException
       *          if the current thread cannot set the context ClassLoader
       *
       * @since 1.2
       */
--- 2305,42 ---
       *
       * @since 1.2
       */
      @CallerSensitive
      public ClassLoader getContextClassLoader() {
!         ClassLoader cl = this.contextClassLoader;
+         if (cl == null)
              return null;
+         if (cl == ClassLoaders.NOT_SUPPORTED)
+             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.
!      * 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> 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
       */

*** 1522,13 ***
--- 2348,32 ---
          @SuppressWarnings("removal")
          SecurityManager sm = System.getSecurityManager();
          if (sm != null) {
              sm.checkPermission(new RuntimePermission("setContextClassLoader"));
          }
+         if (contextClassLoader == ClassLoaders.NOT_SUPPORTED) {
+             throw new UnsupportedOperationException(
+                 "Thread is not allowed to set values for its copy of thread-local variables");
+         }
          contextClassLoader = cl;
      }
  
+     @SuppressWarnings("removal")
+     private static class ClassLoaders {
+         static final ClassLoader NOT_SUPPORTED;
+         static {
+             PrivilegedAction<ClassLoader> pa = new PrivilegedAction<>() {
+                 @Override
+                 public ClassLoader run() {
+                     return new ClassLoader(null) { };
+                 }
+             };
+             NOT_SUPPORTED = AccessController.doPrivileged(pa);
+         }
+     }
+ 
+ 
      /**
       * 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

*** 1588,33 ***
          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[][] stackTraceArray = dumpThreads(new Thread[] {this});
!             StackTraceElement[] stackTrace = stackTraceArray[0];
-             // a thread that was alive during the previous isAlive call may have
-             // since terminated, therefore not having a stacktrace.
-             if (stackTrace == null) {
-                 stackTrace = EMPTY_STACK_TRACE;
-             }
-             return stackTrace;
          } else {
              return (new Exception()).getStackTrace();
          }
      }
  
      /**
!      * Returns a map of stack traces for all live 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.
--- 2433,49 ---
          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.

*** 1649,14 ***
      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);
--- 2510,12 ---
      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);

*** 1736,10 ***
--- 2595,17 ---
              }
          );
          return result.booleanValue();
      }
  
+     /**
+      * Return an array of all live threads.
+      */
+     static Thread[] getAllThreads() {
+         return getThreads();
+     }
+ 
      private static native StackTraceElement[][] dumpThreads(Thread[] threads);
      private static native Thread[] getThreads();
  
      /**
       * Returns the identifier of this Thread.  The thread ID is a positive

*** 1749,11 ***
       *
       * @return this thread's ID.
       * @since 1.5
       */
      public long getId() {
!         return tid;
      }
  
      /**
       * A thread state.  A thread can be in one of the following states:
       * <ul>
--- 2615,13 ---
       *
       * @return this thread's ID.
       * @since 1.5
       */
      public long getId() {
!         // The 16 most significant bits can be used for tracing
+         // so these bits are excluded using TID_MASK.
+         return tid & ThreadIdentifiers.TID_MASK;
      }
  
      /**
       * A thread state.  A thread can be in one of the following states:
       * <ul>

*** 1860,12 ***
       *
       * @return this thread's state.
       * @since 1.5
       */
      public State getState() {
!         // get current thread state
!         return jdk.internal.misc.VM.toThreadState(threadStatus);
      }
  
      // Added in JSR-166
  
      /**
--- 2728,21 ---
       *
       * @return this thread's state.
       * @since 1.5
       */
      public State getState() {
!         return threadState();
!     }
+ 
+     /**
+      * Returns the state of this thread.
+      *
+      * @apiNote For VirtualThread use as getState may be overridden and run
+      * arbitrary code.
+      */
+     State threadState() {
+         return jdk.internal.misc.VM.toThreadState(holder.threadStatus);
      }
  
      // Added in JSR-166
  
      /**

*** 1974,12 ***
       * has terminated, in which case {@code null} is returned.
       * @since 1.5
       * @return the uncaught exception handler for this thread
       */
      public UncaughtExceptionHandler getUncaughtExceptionHandler() {
          return uncaughtExceptionHandler != null ?
!             uncaughtExceptionHandler : group;
      }
  
      /**
       * Set the handler invoked when this thread abruptly terminates
       * due to an uncaught exception.
--- 2851,14 ---
       * has terminated, in which case {@code null} is returned.
       * @since 1.5
       * @return the uncaught exception handler for this thread
       */
      public UncaughtExceptionHandler getUncaughtExceptionHandler() {
+         if (getState() == State.TERMINATED)
+             return null;
          return uncaughtExceptionHandler != null ?
!             uncaughtExceptionHandler : getThreadGroup();
      }
  
      /**
       * Set the handler invoked when this thread abruptly terminates
       * due to an uncaught exception.

*** 1995,18 ***
       * @see ThreadGroup#uncaughtException
       * @since 1.5
       */
      public void setUncaughtExceptionHandler(UncaughtExceptionHandler eh) {
          checkAccess();
!         uncaughtExceptionHandler = eh;
      }
  
      /**
       * Dispatch an uncaught exception to the handler. This method is
!      * intended to be called only by the JVM.
       */
!     private void dispatchUncaughtException(Throwable e) {
          getUncaughtExceptionHandler().uncaughtException(this, e);
      }
  
      /**
       * Removes from the specified map any keys that have been enqueued
--- 2874,22 ---
       * @see ThreadGroup#uncaughtException
       * @since 1.5
       */
      public void setUncaughtExceptionHandler(UncaughtExceptionHandler eh) {
          checkAccess();
!         uncaughtExceptionHandler(eh);
+     }
+ 
+     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);
      }
  
      /**
       * Removes from the specified map any keys that have been enqueued

*** 2068,29 ***
                  return false;
              }
          }
      }
  
  
      // 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, and we can not risk accidental false sharing.
-     // Hence, the fields are isolated with @Contended.
  
      /** The current seed for a ThreadLocalRandom */
-     @jdk.internal.vm.annotation.Contended("tlr")
      long threadLocalRandomSeed;
  
      /** Probe hash value; nonzero if threadLocalRandomSeed initialized */
-     @jdk.internal.vm.annotation.Contended("tlr")
      int threadLocalRandomProbe;
  
      /** Secondary seed isolated from public ThreadLocalRandom sequence */
-     @jdk.internal.vm.annotation.Contended("tlr")
      int threadLocalRandomSecondarySeed;
  
      /* Some private helper methods */
      private native void setPriority0(int newPriority);
      private native void stop0(Object o);
      private native void suspend0();
      private native void resume0();
--- 2951,94 ---
                  return false;
              }
          }
      }
  
+     @SuppressWarnings("removal")
+     private static class VirtualThreads {
+         // Thread group for virtual threads.
+         static final ThreadGroup THREAD_GROUP;
+ 
+         // AccessControlContext that doesn't support any permissions.
+         @SuppressWarnings("removal")
+         static final AccessControlContext ACCESS_CONTROL_CONTEXT;
+ 
+         static {
+             PrivilegedAction<ThreadGroup> pa = new PrivilegedAction<>() {
+                 @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(pa);
+             THREAD_GROUP = new ThreadGroup(root, "VirtualThreads", NORM_PRIORITY);
+ 
+             ACCESS_CONTROL_CONTEXT = new AccessControlContext(new ProtectionDomain[] {
+                 new ProtectionDomain(null, null)
+             });
+         }
+     }
  
      // 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 */
+     @Stable private volatile ThreadContainer container;
+     ThreadContainer threadContainer() {
+         return container;
+     }
+     void setThreadContainer(ThreadContainer container) {
+         // assert this.container == null;
+         this.container = container;
+     }
+ 
+     /** The top of this stack of thread containers owned by this thread */
+     private volatile ThreadContainer headThreadContainer;
+     ThreadContainer headThreadContainer() {
+         return headThreadContainer;
+     }
+     ScopeLocal.Snapshot pushThreadContainer(ThreadContainer container) {
+         container.setPrevious(headThreadContainer);
+         headThreadContainer = container;
+         return scopeLocalBindings;
+     }
+     void popThreadContainer(ThreadContainer container) {
+         ThreadContainer head = headThreadContainer;
+         if (head == container) {
+             // restore ref to previous executor
+             headThreadContainer = head.previous();
+         } else {
+             // pop out of order, uncommon path
+             if (head == null)
+                 throw new InternalError();
+             ThreadContainer next = head;
+             ThreadContainer current = head.previous();
+             while (current != container) {
+                 if (current == null)
+                     throw new InternalError();
+                 next = current;
+                 current = current.previous();
+             }
+             next.setPrevious(current.previous());
+         }
+     }
+ 
      /* Some private helper methods */
      private native void setPriority0(int newPriority);
      private native void stop0(Object o);
      private native void suspend0();
      private native void resume0();
< prev index next >