14 * version 2 for more details (a copy is included in the LICENSE file that
15 * accompanied this code).
16 *
17 * You should have received a copy of the GNU General Public License version
18 * 2 along with this work; if not, write to the Free Software Foundation,
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20 *
21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22 * or visit www.oracle.com if you need additional information or have any
23 * questions.
24 */
25
26 package java.lang;
27
28 import java.lang.ref.Reference;
29 import java.lang.reflect.Field;
30 import java.time.Duration;
31 import java.util.Map;
32 import java.util.HashMap;
33 import java.util.Objects;
34 import java.util.concurrent.ThreadFactory;
35 import java.util.concurrent.StructureViolationException;
36 import java.util.concurrent.locks.LockSupport;
37 import jdk.internal.event.ThreadSleepEvent;
38 import jdk.internal.misc.TerminatingThreadLocal;
39 import jdk.internal.misc.Unsafe;
40 import jdk.internal.misc.VM;
41 import jdk.internal.vm.Continuation;
42 import jdk.internal.vm.ScopedValueContainer;
43 import jdk.internal.vm.StackableScope;
44 import jdk.internal.vm.ThreadContainer;
45 import jdk.internal.vm.annotation.ForceInline;
46 import jdk.internal.vm.annotation.Hidden;
47 import jdk.internal.vm.annotation.IntrinsicCandidate;
48 import jdk.internal.vm.annotation.Stable;
49 import sun.nio.ch.Interruptible;
50 import static java.util.concurrent.TimeUnit.MILLISECONDS;
51 import static java.util.concurrent.TimeUnit.NANOSECONDS;
52
53 /**
54 * A <i>thread</i> is a thread of execution in a program. The Java
55 * virtual machine allows an application to have multiple threads of
56 * execution running concurrently.
57 *
58 * <p> {@code Thread} defines constructors and a {@link Builder} to create threads.
59 * {@linkplain #start() Starting} a thread schedules it to execute its {@link #run() run}
60 * method. The newly started thread executes concurrently with the thread that caused
269
270 // thread name
271 private volatile String name;
272
273 // interrupted status (read/written by VM)
274 volatile boolean interrupted;
275
276 // context ClassLoader
277 private volatile ClassLoader contextClassLoader;
278
279 // Additional fields for platform threads.
280 // All fields, except task and terminatingThreadLocals, are accessed directly by the VM.
281 private static class FieldHolder {
282 final ThreadGroup group;
283 final Runnable task;
284 final long stackSize;
285 volatile int priority;
286 volatile boolean daemon;
287 volatile int threadStatus;
288
289 // This map is maintained by the ThreadLocal class
290 ThreadLocal.ThreadLocalMap terminatingThreadLocals;
291
292 FieldHolder(ThreadGroup group,
293 Runnable task,
294 long stackSize,
295 int priority,
296 boolean daemon) {
297 this.group = group;
298 this.task = task;
299 this.stackSize = stackSize;
300 this.priority = priority;
301 if (daemon)
302 this.daemon = true;
303 }
304 }
305 private final FieldHolder holder;
306
307 ThreadLocal.ThreadLocalMap terminatingThreadLocals() {
308 return holder.terminatingThreadLocals;
309 }
310
311 void setTerminatingThreadLocals(ThreadLocal.ThreadLocalMap map) {
312 holder.terminatingThreadLocals = map;
313 }
314
315 /*
316 * ThreadLocal values pertaining to this thread. This map is maintained
317 * by the ThreadLocal class.
318 */
319 private ThreadLocal.ThreadLocalMap threadLocals;
320
321 ThreadLocal.ThreadLocalMap threadLocals() {
322 return threadLocals;
323 }
324
325 void setThreadLocals(ThreadLocal.ThreadLocalMap map) {
326 threadLocals = map;
327 }
328
329 /*
330 * InheritableThreadLocal values pertaining to this thread. This map is
331 * maintained by the InheritableThreadLocal class.
332 */
333 private ThreadLocal.ThreadLocalMap inheritableThreadLocals;
334
709 static {
710 U = Unsafe.getUnsafe();
711 NEXT_TID_OFFSET = Thread.getNextThreadIdOffset();
712 }
713 static long next() {
714 return U.getAndAddLong(null, NEXT_TID_OFFSET, 1);
715 }
716 }
717
718 /**
719 * Initializes a platform Thread.
720 *
721 * @param g the Thread group, can be null
722 * @param name the name of the new Thread
723 * @param characteristics thread characteristics
724 * @param task the object whose run() method gets called
725 * @param stackSize the desired stack size for the new thread, or
726 * zero to indicate that this parameter is to be ignored.
727 */
728 Thread(ThreadGroup g, String name, int characteristics, Runnable task, long stackSize) {
729
730 Thread parent = currentThread();
731 boolean attached = (parent == this); // primordial or JNI attached
732
733 if (attached) {
734 if (g == null) {
735 throw new InternalError("group cannot be null when attaching");
736 }
737 this.holder = new FieldHolder(g, task, stackSize, NORM_PRIORITY, false);
738 } else {
739 if (g == null) {
740 // default to current thread's group
741 g = parent.getThreadGroup();
742 }
743 int priority = Math.min(parent.getPriority(), g.getMaxPriority());
744 this.holder = new FieldHolder(g, task, stackSize, priority, parent.isDaemon());
745 }
746
747 if (attached && VM.initLevel() < 1) {
748 this.tid = PRIMORDIAL_TID; // primordial thread
749 } else {
793 }
794 this.contextClassLoader = parent.getContextClassLoader();
795 } else {
796 // default CCL to the system class loader when not inheriting
797 this.contextClassLoader = ClassLoader.getSystemClassLoader();
798 }
799
800 // special value to indicate this is a newly-created Thread
801 this.scopedValueBindings = NEW_THREAD_BINDINGS;
802
803 // create a FieldHolder object, needed when bound to an OS thread
804 if (bound) {
805 ThreadGroup g = Constants.VTHREAD_GROUP;
806 int pri = NORM_PRIORITY;
807 this.holder = new FieldHolder(g, null, -1, pri, true);
808 } else {
809 this.holder = null;
810 }
811 }
812
813 /**
814 * Returns a builder for creating a platform {@code Thread} or {@code ThreadFactory}
815 * that creates platform threads.
816 *
817 * @apiNote The following are examples using the builder:
818 * {@snippet :
819 * // Start a daemon thread to run a task
820 * Thread thread = Thread.ofPlatform().daemon().start(runnable);
821 *
822 * // Create an unstarted thread with name "duke", its start() method
823 * // must be invoked to schedule it to execute.
824 * Thread thread = Thread.ofPlatform().name("duke").unstarted(runnable);
825 *
826 * // A ThreadFactory that creates daemon threads named "worker-0", "worker-1", ...
827 * ThreadFactory factory = Thread.ofPlatform().daemon().name("worker-", 0).factory();
828 * }
829 *
830 * @return A builder for creating {@code Thread} or {@code ThreadFactory} objects.
831 * @since 21
832 */
1047 * that creates virtual threads.
1048 *
1049 * <p> Unless otherwise specified, passing a null argument to a method in
1050 * this interface causes a {@code NullPointerException} to be thrown.
1051 *
1052 * @see Thread#ofVirtual()
1053 * @since 21
1054 */
1055 sealed interface OfVirtual extends Builder
1056 permits ThreadBuilders.VirtualThreadBuilder {
1057
1058 @Override OfVirtual name(String name);
1059
1060 /**
1061 * @throws IllegalArgumentException {@inheritDoc}
1062 */
1063 @Override OfVirtual name(String prefix, long start);
1064
1065 @Override OfVirtual inheritInheritableThreadLocals(boolean inherit);
1066 @Override OfVirtual uncaughtExceptionHandler(UncaughtExceptionHandler ueh);
1067 }
1068 }
1069
1070 /**
1071 * Throws CloneNotSupportedException as a Thread can not be meaningfully
1072 * cloned. Construct a new Thread instead.
1073 *
1074 * @throws CloneNotSupportedException
1075 * always
1076 */
1077 @Override
1078 protected Object clone() throws CloneNotSupportedException {
1079 throw new CloneNotSupportedException();
1080 }
1081
1082 /**
1083 * Helper class for auto-numbering platform threads. The numbers start at
1084 * 0 and are separate from the thread identifier for historical reasons.
1085 */
1086 private static class ThreadNumbering {
1408 public Thread(ThreadGroup group, Runnable task, String name,
1409 long stackSize, boolean inheritInheritableThreadLocals) {
1410 this(group, checkName(name),
1411 (inheritInheritableThreadLocals ? 0 : NO_INHERIT_THREAD_LOCALS),
1412 task, stackSize);
1413 }
1414
1415 /**
1416 * Creates a virtual thread to execute a task and schedules it to execute.
1417 *
1418 * <p> This method is equivalent to:
1419 * <pre>{@code Thread.ofVirtual().start(task); }</pre>
1420 *
1421 * @param task the object to run when the thread executes
1422 * @return a new, and started, virtual thread
1423 * @see <a href="#inheritance">Inheritance when creating threads</a>
1424 * @since 21
1425 */
1426 public static Thread startVirtualThread(Runnable task) {
1427 Objects.requireNonNull(task);
1428 var thread = ThreadBuilders.newVirtualThread(null, null, 0, task);
1429 thread.start();
1430 return thread;
1431 }
1432
1433 /**
1434 * Returns {@code true} if this thread is a virtual thread. A virtual thread
1435 * is scheduled by the Java virtual machine rather than the operating system.
1436 *
1437 * @return {@code true} if this thread is a virtual thread
1438 *
1439 * @since 21
1440 */
1441 public final boolean isVirtual() {
1442 return (this instanceof BaseVirtualThread);
1443 }
1444
1445 /**
1446 * Schedules this thread to begin execution. The thread will execute
1447 * independently of the current thread.
1448 *
|
14 * version 2 for more details (a copy is included in the LICENSE file that
15 * accompanied this code).
16 *
17 * You should have received a copy of the GNU General Public License version
18 * 2 along with this work; if not, write to the Free Software Foundation,
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20 *
21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22 * or visit www.oracle.com if you need additional information or have any
23 * questions.
24 */
25
26 package java.lang;
27
28 import java.lang.ref.Reference;
29 import java.lang.reflect.Field;
30 import java.time.Duration;
31 import java.util.Map;
32 import java.util.HashMap;
33 import java.util.Objects;
34 import java.util.concurrent.RejectedExecutionException;
35 import java.util.concurrent.ThreadFactory;
36 import java.util.concurrent.StructureViolationException;
37 import java.util.concurrent.locks.LockSupport;
38 import jdk.internal.event.ThreadSleepEvent;
39 import jdk.internal.javac.Restricted;
40 import jdk.internal.misc.TerminatingThreadLocal;
41 import jdk.internal.misc.Unsafe;
42 import jdk.internal.misc.VM;
43 import jdk.internal.reflect.CallerSensitive;
44 import jdk.internal.reflect.Reflection;
45 import jdk.internal.vm.Continuation;
46 import jdk.internal.vm.ScopedValueContainer;
47 import jdk.internal.vm.StackableScope;
48 import jdk.internal.vm.ThreadContainer;
49 import jdk.internal.vm.annotation.ForceInline;
50 import jdk.internal.vm.annotation.Hidden;
51 import jdk.internal.vm.annotation.IntrinsicCandidate;
52 import jdk.internal.vm.annotation.Stable;
53 import sun.nio.ch.Interruptible;
54 import static java.util.concurrent.TimeUnit.MILLISECONDS;
55 import static java.util.concurrent.TimeUnit.NANOSECONDS;
56
57 /**
58 * A <i>thread</i> is a thread of execution in a program. The Java
59 * virtual machine allows an application to have multiple threads of
60 * execution running concurrently.
61 *
62 * <p> {@code Thread} defines constructors and a {@link Builder} to create threads.
63 * {@linkplain #start() Starting} a thread schedules it to execute its {@link #run() run}
64 * method. The newly started thread executes concurrently with the thread that caused
273
274 // thread name
275 private volatile String name;
276
277 // interrupted status (read/written by VM)
278 volatile boolean interrupted;
279
280 // context ClassLoader
281 private volatile ClassLoader contextClassLoader;
282
283 // Additional fields for platform threads.
284 // All fields, except task and terminatingThreadLocals, are accessed directly by the VM.
285 private static class FieldHolder {
286 final ThreadGroup group;
287 final Runnable task;
288 final long stackSize;
289 volatile int priority;
290 volatile boolean daemon;
291 volatile int threadStatus;
292
293 // Used by NativeThread for signalling, set lazily, read from any thread
294 @Stable long nativeThreadID;
295
296 // This map is maintained by the ThreadLocal class
297 ThreadLocal.ThreadLocalMap terminatingThreadLocals;
298
299 FieldHolder(ThreadGroup group,
300 Runnable task,
301 long stackSize,
302 int priority,
303 boolean daemon) {
304 this.group = group;
305 this.task = task;
306 this.stackSize = stackSize;
307 this.priority = priority;
308 if (daemon)
309 this.daemon = true;
310 }
311 }
312 private final FieldHolder holder;
313
314 ThreadLocal.ThreadLocalMap terminatingThreadLocals() {
315 return holder.terminatingThreadLocals;
316 }
317
318 void setTerminatingThreadLocals(ThreadLocal.ThreadLocalMap map) {
319 holder.terminatingThreadLocals = map;
320 }
321
322 long nativeThreadID() {
323 return holder.nativeThreadID;
324 }
325
326 void setNativeThreadID(long id) {
327 holder.nativeThreadID = id;
328 }
329
330 /*
331 * ThreadLocal values pertaining to this thread. This map is maintained
332 * by the ThreadLocal class.
333 */
334 private ThreadLocal.ThreadLocalMap threadLocals;
335
336 ThreadLocal.ThreadLocalMap threadLocals() {
337 return threadLocals;
338 }
339
340 void setThreadLocals(ThreadLocal.ThreadLocalMap map) {
341 threadLocals = map;
342 }
343
344 /*
345 * InheritableThreadLocal values pertaining to this thread. This map is
346 * maintained by the InheritableThreadLocal class.
347 */
348 private ThreadLocal.ThreadLocalMap inheritableThreadLocals;
349
724 static {
725 U = Unsafe.getUnsafe();
726 NEXT_TID_OFFSET = Thread.getNextThreadIdOffset();
727 }
728 static long next() {
729 return U.getAndAddLong(null, NEXT_TID_OFFSET, 1);
730 }
731 }
732
733 /**
734 * Initializes a platform Thread.
735 *
736 * @param g the Thread group, can be null
737 * @param name the name of the new Thread
738 * @param characteristics thread characteristics
739 * @param task the object whose run() method gets called
740 * @param stackSize the desired stack size for the new thread, or
741 * zero to indicate that this parameter is to be ignored.
742 */
743 Thread(ThreadGroup g, String name, int characteristics, Runnable task, long stackSize) {
744 Thread parent = currentThread();
745 boolean attached = (parent == this); // primordial or JNI attached
746
747 if (attached) {
748 if (g == null) {
749 throw new InternalError("group cannot be null when attaching");
750 }
751 this.holder = new FieldHolder(g, task, stackSize, NORM_PRIORITY, false);
752 } else {
753 if (g == null) {
754 // default to current thread's group
755 g = parent.getThreadGroup();
756 }
757 int priority = Math.min(parent.getPriority(), g.getMaxPriority());
758 this.holder = new FieldHolder(g, task, stackSize, priority, parent.isDaemon());
759 }
760
761 if (attached && VM.initLevel() < 1) {
762 this.tid = PRIMORDIAL_TID; // primordial thread
763 } else {
807 }
808 this.contextClassLoader = parent.getContextClassLoader();
809 } else {
810 // default CCL to the system class loader when not inheriting
811 this.contextClassLoader = ClassLoader.getSystemClassLoader();
812 }
813
814 // special value to indicate this is a newly-created Thread
815 this.scopedValueBindings = NEW_THREAD_BINDINGS;
816
817 // create a FieldHolder object, needed when bound to an OS thread
818 if (bound) {
819 ThreadGroup g = Constants.VTHREAD_GROUP;
820 int pri = NORM_PRIORITY;
821 this.holder = new FieldHolder(g, null, -1, pri, true);
822 } else {
823 this.holder = null;
824 }
825 }
826
827 /**
828 * The task that a {@linkplain VirtualThreadScheduler virtual thread scheduler}
829 * executes on a platform thread to
830 * {@linkplain VirtualThreadScheduler#onStart(VirtualThreadTask) start}
831 * or {@linkplain VirtualThreadScheduler#onContinue(VirtualThreadTask) continue}
832 * execution of a virtual thread. While executing the task, the platform thread is
833 * the virtual thread's <em>carrier</em>.
834 *
835 * <p> There is a {@code VirtualThreadTask} object for each virtual thread. The
836 * scheduler arranges to execute its {@link #run()} method when called to start or
837 * continue the virtual thread, if possible on the {@linkplain #preferredCarrier()
838 * preferred carrier thread}. The scheduler may attach an object to the task.
839 *
840 * @since 99
841 */
842 public sealed interface VirtualThreadTask extends Runnable permits
843 VirtualThread.BuiltinSchedulerTask, VirtualThread.CustomSchedulerTask {
844
845 /**
846 * {@return the virtual thread that this task starts or continues}
847 */
848 Thread thread();
849
850 /**
851 * Runs the task on the current thread as the carrier thread.
852 *
853 * <p> Invoking this method with the interrupted status set will first
854 * clear the interrupt status. Interrupting the carrier thread while
855 * running the task leads to unspecified behavior.
856 *
857 * @throws IllegalStateException if the virtual thread is not in a state to
858 * run on the current thread
859 * @throws IllegalCallerException if the current thread is a virtual thread
860 */
861 @Override
862 void run();
863
864 /**
865 * Returns the preferred carrier thread to execute this task. The scheduler may
866 * choose to ignore this preference.
867 * @return the preferred carrier thread or {@code null} if there is no preferred
868 * carrier thread
869 */
870 Thread preferredCarrier();
871
872 /**
873 * Attaches the given object to this task.
874 * @param att the object to attach
875 * @return the previously-attached object, if any, otherwise {@code null}
876 */
877 Object attach(Object att);
878
879 /**
880 * Retrieves the current attachment.
881 * @return the object currently attached to this task or {@code null} if
882 * there is no attachment
883 */
884 Object attachment();
885 }
886
887 /**
888 * Virtual thread scheduler.
889 *
890 * @apiNote The following example creates a virtual thread scheduler that uses a small
891 * set of platform threads.
892 * {@snippet lang=java :
893 * ExecutorService threadPool = Executors.newFixedThreadPool(4);
894 * var scheduler = new VirtualThreadScheduler() {
895 * private void submit(VirtualThreadTask task) {
896 * Thread caller = Thread.currentThread();
897 * threadPool.submit(() -> {
898 * Thread vthread = task.thread();
899 * Thread carrier = Thread.currentThread();
900 * try {
901 * task.run();
902 * } finally {
903 * assert Thread.currentThread() == carrier;
904 * boolean terminated = !vthread.isAlive();
905 * }
906 * });
907 * }
908 * @Override
909 * public void onStart(VirtualThreadTask task) {
910 * submit(task);
911 * }
912 * @Override
913 * public void onContinue(VirtualThreadTask task) {
914 * submit(task);
915 * }
916 * };
917 * }
918 *
919 * <p> Unless otherwise specified, passing a null argument to a method in
920 * this interface causes a {@code NullPointerException} to be thrown.
921 *
922 * @see Builder.OfVirtual#scheduler(VirtualThreadScheduler)
923 * @since 99
924 * @see VirtualThreadScheduler
925 */
926 public interface VirtualThreadScheduler {
927 /**
928 * Invoked by {@link Thread#start()} to start execution of a {@linkplain
929 * VirtualThreadTask#thread() virtual thread}.
930 * The scheduler's implementation of this method must arrange to execute the
931 * given task's {@link VirtualThreadTask#run() run()} method on a platform thread.
932 *
933 * @implNote If invoked from a virtual thread, then the caller virtual thread is
934 * <em>pinned</em> to its carrier while executing the {@code onStart} method.
935 *
936 * @param task the task to execute
937 * @throws RejectedExecutionException if the scheduler cannot accept the task
938 */
939 void onStart(VirtualThreadTask task);
940
941 /**
942 * Invoked to continue execution of a {@linkplain VirtualThreadTask#thread()
943 * virtual thread}.
944 * The scheduler's implementation of this method must arrange to execute the
945 * given task's {@link VirtualThreadTask#run() run()} method on a platform thread.
946 *
947 * @implNote If invoked from a virtual thread, then the caller virtual thread is
948 * <em>pinned</em> to its carrier while executing the {@code onContinue} method.
949 *
950 * @param task the task to execute
951 * @throws RejectedExecutionException if the scheduler cannot accept the task
952 */
953 void onContinue(VirtualThreadTask task);
954
955 // -- prototype 2 --
956
957 /**
958 * {@return the virtual thread scheduler for the current virtual thread}
959 * @throws UnsupportedOperationException if the current thread is not a virtual
960 * thread or scheduling virtual threads to a user-provided scheduler is not
961 * supported by this VM
962 */
963 @CallerSensitive
964 @Restricted
965 static VirtualThreadScheduler current() {
966 Class<?> caller = Reflection.getCallerClass();
967 caller.getModule().ensureNativeAccess(VirtualThreadScheduler.class,
968 "current",
969 caller,
970 false);
971 if (Thread.currentThread() instanceof VirtualThread vthread) {
972 return vthread.scheduler(false);
973 } else {
974 throw new UnsupportedOperationException();
975 }
976 }
977 }
978
979 /**
980 * Returns a builder for creating a platform {@code Thread} or {@code ThreadFactory}
981 * that creates platform threads.
982 *
983 * @apiNote The following are examples using the builder:
984 * {@snippet :
985 * // Start a daemon thread to run a task
986 * Thread thread = Thread.ofPlatform().daemon().start(runnable);
987 *
988 * // Create an unstarted thread with name "duke", its start() method
989 * // must be invoked to schedule it to execute.
990 * Thread thread = Thread.ofPlatform().name("duke").unstarted(runnable);
991 *
992 * // A ThreadFactory that creates daemon threads named "worker-0", "worker-1", ...
993 * ThreadFactory factory = Thread.ofPlatform().daemon().name("worker-", 0).factory();
994 * }
995 *
996 * @return A builder for creating {@code Thread} or {@code ThreadFactory} objects.
997 * @since 21
998 */
1213 * that creates virtual threads.
1214 *
1215 * <p> Unless otherwise specified, passing a null argument to a method in
1216 * this interface causes a {@code NullPointerException} to be thrown.
1217 *
1218 * @see Thread#ofVirtual()
1219 * @since 21
1220 */
1221 sealed interface OfVirtual extends Builder
1222 permits ThreadBuilders.VirtualThreadBuilder {
1223
1224 @Override OfVirtual name(String name);
1225
1226 /**
1227 * @throws IllegalArgumentException {@inheritDoc}
1228 */
1229 @Override OfVirtual name(String prefix, long start);
1230
1231 @Override OfVirtual inheritInheritableThreadLocals(boolean inherit);
1232 @Override OfVirtual uncaughtExceptionHandler(UncaughtExceptionHandler ueh);
1233
1234 // -- prototype 1 --
1235
1236 /**
1237 * Creates a new virtual {@code Thread} from the current state of the builder
1238 * to run the given task. The {@code Thread}'s {@link Thread#start() start}
1239 * method must be invoked to schedule the thread to execute.
1240 * The {@code preferredCarrier} parameter is the preferred carrier thread to
1241 * execute the {@linkplain VirtualThreadTask task} for the virtual thread.
1242 * The scheduler may choose to ignore this preference. The {@code att} is the
1243 * object to attach to the task.
1244 *
1245 * @param task the object to run when the thread executes
1246 * @param preferredCarrier the preferred carrier thread, can be {@code null}
1247 * @param att the object to attach, can be {@code null}
1248 * @return a new unstarted Thread
1249 * @since 99
1250 *
1251 * @see <a href="Thread.html#inheritance">Inheritance when creating threads</a>
1252 */
1253 @CallerSensitive
1254 @Restricted
1255 Thread unstarted(Runnable task, Thread preferredCarrier, Object att);
1256
1257 // -- prototype 2 --
1258
1259 /**
1260 * Sets the scheduler.
1261 *
1262 * <p> The virtual thread will be scheduled by the Java virtual machine with
1263 * the given scheduler. The scheduler's {@link
1264 * VirtualThreadScheduler#onStart(VirtualThreadTask) onStart} and
1265 * {@link VirtualThreadScheduler#onContinue(VirtualThreadTask) onContinue}
1266 * methods may be invoked in the context of a virtual thread. The scheduler
1267 * must arrange to execute the {@link VirtualThreadTask}'s
1268 * {@code run} method on a platform thread. Attempting to execute the run
1269 * method in a virtual thread causes {@link WrongThreadException} to be thrown.
1270 * The {@code onStart} and {@code onContinue }methods may be invoked at
1271 * sensitive times (e.g. when unparking a thread) so care should be taken to
1272 * not directly execute the task on the <em>current thread</em>.
1273 *
1274 * @param scheduler the scheduler
1275 * @return this builder
1276 * @throws UnsupportedOperationException if scheduling virtual threads to a
1277 * user-provided scheduler is not supported by this VM
1278 * @since 99
1279 */
1280 @CallerSensitive
1281 @Restricted
1282 OfVirtual scheduler(VirtualThreadScheduler scheduler);
1283 }
1284 }
1285
1286 /**
1287 * Throws CloneNotSupportedException as a Thread can not be meaningfully
1288 * cloned. Construct a new Thread instead.
1289 *
1290 * @throws CloneNotSupportedException
1291 * always
1292 */
1293 @Override
1294 protected Object clone() throws CloneNotSupportedException {
1295 throw new CloneNotSupportedException();
1296 }
1297
1298 /**
1299 * Helper class for auto-numbering platform threads. The numbers start at
1300 * 0 and are separate from the thread identifier for historical reasons.
1301 */
1302 private static class ThreadNumbering {
1624 public Thread(ThreadGroup group, Runnable task, String name,
1625 long stackSize, boolean inheritInheritableThreadLocals) {
1626 this(group, checkName(name),
1627 (inheritInheritableThreadLocals ? 0 : NO_INHERIT_THREAD_LOCALS),
1628 task, stackSize);
1629 }
1630
1631 /**
1632 * Creates a virtual thread to execute a task and schedules it to execute.
1633 *
1634 * <p> This method is equivalent to:
1635 * <pre>{@code Thread.ofVirtual().start(task); }</pre>
1636 *
1637 * @param task the object to run when the thread executes
1638 * @return a new, and started, virtual thread
1639 * @see <a href="#inheritance">Inheritance when creating threads</a>
1640 * @since 21
1641 */
1642 public static Thread startVirtualThread(Runnable task) {
1643 Objects.requireNonNull(task);
1644 var thread = ThreadBuilders.newVirtualThread(null, 0, task);
1645 thread.start();
1646 return thread;
1647 }
1648
1649 /**
1650 * Returns {@code true} if this thread is a virtual thread. A virtual thread
1651 * is scheduled by the Java virtual machine rather than the operating system.
1652 *
1653 * @return {@code true} if this thread is a virtual thread
1654 *
1655 * @since 21
1656 */
1657 public final boolean isVirtual() {
1658 return (this instanceof BaseVirtualThread);
1659 }
1660
1661 /**
1662 * Schedules this thread to begin execution. The thread will execute
1663 * independently of the current thread.
1664 *
|