< prev index next >

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

Print this page
@@ -28,240 +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
+  * 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;
-  *         }
+  * <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);
   *
-  *         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.
+  *   // 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.
   *
-  * @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;
+     /* Reserved for exclusive use by the JVM, TBD: move to FieldHolder */
+     private long eetop;
  
-     /* Interrupt state of the thread - read/written directly by JVM */
-     private volatile boolean interrupted;
+     // 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;
  
-     /* Fields reserved for exclusive use by the JVM */
-     private boolean stillborn = false;
-     private long eetop;
+     // interrupt status (read/written by VM)
+     volatile boolean interrupted;
  
-     /* What will be run. */
-     private Runnable target;
+     // thread name
+     private volatile String name;
  
-     /* The group of this thread */
-     private ThreadGroup group;
+     // thread id
+     private final long tid;
  
-     /* The context ClassLoader for this thread */
-     private ClassLoader contextClassLoader;
+     // context ClassLoader
+     private volatile ClassLoader contextClassLoader;
  
-     /* The inherited AccessControlContext of this thread */
+     // inherited AccessControlContext, TBD: move this to FieldHolder
      @SuppressWarnings("removal")
      private AccessControlContext inheritedAccessControlContext;
  
-     /* For autonumbering anonymous threads. */
-     private static int threadInitNumber;
-     private static synchronized int nextThreadNum() {
-         return threadInitNumber++;
+     /* 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 = null;
+     ThreadLocal.ThreadLocalMap threadLocals;
  
      /*
       * InheritableThreadLocal values pertaining to this thread. This map is
       * maintained by the InheritableThreadLocal class.
       */
-     ThreadLocal.ThreadLocalMap inheritableThreadLocals = null;
+     ThreadLocal.ThreadLocalMap inheritableThreadLocals;
  
-     /*
-      * 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;
+     // 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;
  
-     /*
-      * Thread ID
-      */
-     private final long tid;
+     ScopeLocal.Snapshot scopeLocalBindings = ScopeLocal.EmptySnapshot.getInstance();
  
-     /* For generating thread ID */
-     private static long threadSeqNumber;
- 
-     private static synchronized long nextThreadID() {
-         return ++threadSeqNumber;
+     /**
+      * 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);
+         }
      }
  
      /*
-      * Java thread status for tools, default indicates thread 'not yet started'
+      * Lock object for thread interrupt.
       */
-     private volatile int threadStatus;
+     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
       */
-     volatile Object parkBlocker;
+     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.
       */
-     private volatile Interruptible blocker;
-     private final Object blockerLock = new Object();
+     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.blockerLock) {
-             me.blocker = b;
+         synchronized (me.interruptLock) {
+             me.nioBlocker = b;
          }
      }
  
      /**
-      * The minimum priority that a thread can have.
+      * 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 thread can have.
+      * The maximum priority that a platform thread can have.
       */
      public static final int MAX_PRIORITY = 10;
  
      /**
-      * Returns a reference to the currently executing thread object.
-      *
-      * @return  the currently executing thread.
+      * 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 +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 native void yield();
+     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 +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 native void sleep(long millis) throws InterruptedException;
+     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 +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 {
+     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");
+             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 +565,45 @@
       */
      @IntrinsicCandidate
      public static void onSpinWait() {}
  
      /**
-      * Initializes a Thread.
+      * 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 target the object whose run() method gets called
       * @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
-      * @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) {
+     Thread(ThreadGroup g, String name, int characteristics, Runnable task,
+            long stackSize, AccessControlContext acc) {
          if (name == null) {
              throw new NullPointerException("name cannot be null");
          }
  
-         this.name = name;
- 
          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 +613,12 @@
              }
  
              /* If the security manager doesn't have a strong opinion
                 on the matter, use the parent thread group. */
              if (g == null) {
-                 g = parent.getThreadGroup();
+                 // avoid parent.getThreadGroup() during early startup
+                 g = getCurrentThreadGroup();
              }
          }
  
          /*
           * Do we have the required permissions?

@@ -429,31 +632,382 @@
                  security.checkPermission(
                          SecurityConstants.SUBCLASS_IMPLEMENTATION_PERMISSION);
              }
          }
  
-         g.addUnstarted();
+         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();
+             }
+         }
  
-         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;
+         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);
+     }
  
-         /* Set thread ID */
-         this.tid = nextThreadID();
+     /**
+      * 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 +1019,113 @@
      protected Object clone() throws CloneNotSupportedException {
          throw new CloneNotSupportedException();
      }
  
      /**
-      * Allocates a new {@code Thread} object. This constructor has the same
+      * 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, "Thread-" + nextThreadNum(), 0);
+         this(null, null, nextThreadName(), 0);
      }
  
      /**
-      * Allocates a new {@code Thread} object. This constructor has the same
+      * Allocates a new platform {@code Thread}. This constructor has the same
       * effect as {@linkplain #Thread(ThreadGroup,Runnable,String) Thread}
-      * {@code (null, target, gname)}, where {@code gname} is a newly generated
+      * {@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.
       *
-      * @param  target
+      * <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 target) {
-         this(null, target, "Thread-" + nextThreadNum(), 0);
+     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 target, @SuppressWarnings("removal") AccessControlContext acc) {
-         this(null, target, "Thread-" + nextThreadNum(), 0, acc, false);
+     Thread(Runnable task, @SuppressWarnings("removal") AccessControlContext acc) {
+         this(null, nextThreadName(), 0, task, 0, acc);
      }
  
      /**
-      * Allocates a new {@code Thread} object. This constructor has the same
+      * Allocates a new platform {@code Thread}. This constructor has the same
       * effect as {@linkplain #Thread(ThreadGroup,Runnable,String) Thread}
-      * {@code (group, target, gname)} ,where {@code gname} is a newly generated
+      * {@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  target
+      * @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 target) {
-         this(group, target, "Thread-" + nextThreadNum(), 0);
+     public Thread(ThreadGroup group, Runnable task) {
+         this(group, task, nextThreadName(), 0);
      }
  
      /**
-      * Allocates a new {@code Thread} object. This constructor has the same
+      * 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 {@code Thread} object. This constructor has the same
+      * 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 +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 {@code Thread} object. This constructor has the same
+      * Allocates a new platform {@code Thread}. This constructor has the same
       * effect as {@linkplain #Thread(ThreadGroup,Runnable,String) Thread}
-      * {@code (null, target, name)}.
+      * {@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  target
+      * @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 target, String name) {
-         this(null, target, name, 0);
+     public Thread(Runnable task, String name) {
+         this(null, task, name, 0);
      }
  
      /**
-      * Allocates a new {@code Thread} object so that it has {@code target}
+      * 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 +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 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 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  target
+      * @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 target, String name) {
-         this(group, target, name, 0);
+     public Thread(ThreadGroup group, Runnable task, String name) {
+         this(group, task, name, 0);
      }
  
      /**
-      * Allocates a new {@code Thread} object so that it has {@code target}
+      * 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 +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  target
+      * @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 +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 target, String name,
-                   long stackSize) {
-         this(group, target, name, stackSize, null, true);
+     public Thread(ThreadGroup group, Runnable task, String name, long stackSize) {
+         this(group, name, 0, task, stackSize, null);
      }
  
      /**
-      * Allocates a new {@code Thread} object so that it has {@code target}
+      * 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 +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  target
+      * @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  inheritThreadLocals
+      * @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 target, String name,
-                   long stackSize, boolean inheritThreadLocals) {
-         this(group, target, name, stackSize, null, inheritThreadLocals);
+     public Thread(ThreadGroup group, Runnable task, String name,
+                   long stackSize, boolean inheritInheritableThreadLocals) {
+         this(group, name,
+                 (inheritInheritableThreadLocals ? 0 : NO_INHERIT_THREAD_LOCALS),
+                 task, stackSize, null);
      }
  
      /**
-      * 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).
+      * 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.
-      * @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();
+      * @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();
+         }
+     }
  
-         /* 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);
+     /**
+      * 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;
-         try {
-             start0();
-             started = true;
-         } finally {
+             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) {
-                     group.threadStartFailed(this);
+                     container.onExit(this);
                  }
-             } catch (Throwable ignore) {
-                 /* do nothing. If start0 threw a Throwable then
-                   it will be passed up the call stack */
              }
          }
      }
  
      private native void start0();

@@ -818,44 +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     #stop()
       * @see     #Thread(ThreadGroup, Runnable, String)
       */
      @Override
      public void run() {
-         if (target != null) {
-             target.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() {
-         if (threadLocals != null && TerminatingThreadLocal.REGISTRY.isPresent()) {
-             TerminatingThreadLocal.threadTerminated();
+         ThreadContainer container = threadContainer();
+         if (container != null) {
+             container.onExit(this);
          }
-         if (group != null) {
-             group.threadTerminated(this);
-             group = null;
+ 
+         try {
+             if (threadLocals != null && TerminatingThreadLocal.REGISTRY.isPresent()) {
+                 TerminatingThreadLocal.threadTerminated();
+             }
+         } finally {
+             clearReferences();
          }
-         /* 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>

@@ -882,21 +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 dies).  If a {@code catch} clause catches a
+      * officially terminates).  If a {@code catch} clause catches a
       * {@code ThreadDeath} object, it is important to rethrow the
-      * object so that the thread actually dies.
+      * 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 +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")
+     @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 (threadStatus != 0) {
+         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 +1654,22 @@
      public void interrupt() {
          if (this != Thread.currentThread()) {
              checkAccess();
  
              // thread may be blocked in an I/O operation
-             synchronized (blockerLock) {
-                 Interruptible b = blocker;
+             synchronized (interruptLock) {
+                 Interruptible b = nioBlocker;
                  if (b != null) {
                      interrupted = true;
                      interrupt0();  // inform VM of interrupt
                      b.interrupt(this);
                      return;
                  }
              }
          }
          interrupted = true;
-         // inform VM of interrupt
-         interrupt0();
+         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 +1682,11 @@
       *          {@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;
+         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 +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 died.
+      * been started and has not yet terminated.
       *
       * @return  {@code true} if this thread is alive;
       *          {@code false} otherwise.
       */
-     public final native boolean isAlive();
+     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 +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.
-      * <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()
+      *
+      * 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) {
-         ThreadGroup g;
          checkAccess();
          if (newPriority > MAX_PRIORITY || newPriority < MIN_PRIORITY) {
              throw new IllegalArgumentException();
          }
-         if((g = getThreadGroup()) != null) {
-             if (newPriority > g.getMaxPriority()) {
-                 newPriority = g.getMaxPriority();
+         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(priority = newPriority);
+             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() {
-         return priority;
+         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 +1886,11 @@
          if (name == null) {
              throw new NullPointerException("name cannot be null");
          }
  
          this.name = name;
-         if (threadStatus != 0) {
+         if (!isVirtual() && Thread.currentThread() == this) {
              setNativeName(name);
          }
      }
  
      /**

@@ -1190,44 +1903,67 @@
          return name;
      }
  
      /**
       * Returns the thread group to which this thread belongs.
-      * This method returns null if this thread has died
-      * (been stopped).
+      * This method returns null if the thread has terminated.
       *
       * @return  this thread's thread group.
       */
      public final ThreadGroup getThreadGroup() {
-         return group;
+         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. Recursively iterates over all subgroups in the current
-      * thread's thread group.
+      * 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.
+      * 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 +2007,18 @@
      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.
+      * 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}.
       *
-      * <p> This implementation uses a loop of {@code this.wait} calls
-      * conditioned on {@code this.isAlive}. As a thread terminates the
+      * @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 +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 synchronized void join(final long millis)
-     throws InterruptedException {
-         if (millis > 0) {
+     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()) {
-                 final long startTime = System.nanoTime();
-                 long delay = millis;
-                 do {
-                     wait(delay);
-                 } while (isAlive() && (delay = millis -
-                         TimeUnit.NANOSECONDS.toMillis(System.nanoTime() - startTime)) > 0);
+                 long nanos = MILLISECONDS.toNanos(millis);
+                 vthread.joinNanos(nanos);
              }
-         } else if (millis == 0) {
-             while (isAlive()) {
-                 wait(0);
+             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);
+                 }
              }
-         } else {
-             throw new IllegalArgumentException("timeout value is negative");
          }
      }
  
      /**
       * Waits at most {@code millis} milliseconds plus
-      * {@code nanos} nanoseconds for this thread to die.
+      * {@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}.
       *
-      * <p> This implementation uses a loop of {@code this.wait} calls
-      * conditioned on {@code this.isAlive}. As a thread terminates the
+      * @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 +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 synchronized void join(long millis, int nanos)
-     throws InterruptedException {
- 
+     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");
+             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.
+      * Waits for this thread to terminate.
       *
       * <p> An invocation of this method behaves in exactly the same
       * way as the invocation
       *
       * <blockquote>

@@ -1370,52 +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 used only for debugging.
+      * This method is useful 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.
+      * 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.
       *
-      * <p> This method must be invoked before the thread is started.
+      * 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 (isAlive()) {
+         if (isVirtual() && !on)
+             throw new IllegalArgumentException("'false' not legal for virtual threads");
+         if (isAlive())
              throw new IllegalThreadStateException();
-         }
-         daemon = on;
+         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() {
-         return daemon;
+         if (isVirtual()) {
+             return true;
+         } else {
+             return holder.daemon;
+         }
      }
  
      /**
       * Determines if the currently running thread has permission to
       * modify this thread.

@@ -1442,36 +2259,41 @@
              security.checkAccess(this);
          }
      }
  
      /**
-      * Returns a string representation of this thread, including the
-      * thread's name, priority, and thread group.
+      * 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) {
-             return "Thread[" + getName() + "," + getPriority() + "," +
-                            group.getName() + "]";
-         } else {
-             return "Thread[" + getName() + "," + getPriority() + "," +
-                             "" + "]";
-         }
+         if (group != null)
+             sb.append(group.getName());
+         sb.append("]");
+         return sb.toString();
      }
  
      /**
-      * 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.
+      * 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 +2305,42 @@
       *
       * @since 1.2
       */
      @CallerSensitive
      public ClassLoader getContextClassLoader() {
-         if (contextClassLoader == null)
+         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) {
-             ClassLoader.checkClassLoaderPermission(contextClassLoader,
-                                                    Reflection.getCallerClass());
+             Class<?> caller = Reflection.getCallerClass();
+             ClassLoader.checkClassLoaderPermission(cl, caller);
          }
-         return contextClassLoader;
+         return cl;
      }
  
      /**
-      * 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.
+      * 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
+      * <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 +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);
+                 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;
+             StackTraceElement[] stackTrace = asyncGetStackTrace();
+             return (stackTrace != null) ? stackTrace : EMPTY_STACK_TRACE;
          } else {
              return (new Exception()).getStackTrace();
          }
      }
  
      /**
-      * Returns a map of stack traces for all live threads.
+      * 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 +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);
+             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 +2615,13 @@
       *
       * @return this thread's ID.
       * @since 1.5
       */
      public long getId() {
-         return tid;
+         // 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 +2728,21 @@
       *
       * @return this thread's state.
       * @since 1.5
       */
      public State getState() {
-         // get current thread state
-         return jdk.internal.misc.VM.toThreadState(threadStatus);
+         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 +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 : group;
+             uncaughtExceptionHandler : getThreadGroup();
      }
  
      /**
       * Set the handler invoked when this thread abruptly terminates
       * due to an uncaught exception.

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

@@ -2068,29 +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, and we can not risk accidental false sharing.
-     // Hence, the fields are isolated with @Contended.
+     // concurrent code.
  
      /** 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;
  
+     /** 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 >