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
61 * it to start.
62 *
63 * <p> A thread <i>terminates</i> if either its {@code run} method completes normally,
64 * or if its {@code run} method completes abruptly and the appropriate {@linkplain
65 * Thread.UncaughtExceptionHandler uncaught exception handler} completes normally or
66 * abruptly. With no code left to run, the thread has completed execution. The
67 * {@link #join() join} method can be used to wait for a thread to terminate.
68 *
69 * <p> Threads have a unique {@linkplain #threadId() identifier} and a {@linkplain
158 * status and thread priority from the parent thread at the time that the child {@code
159 * Thread} is created. The {@linkplain ThreadGroup thread group} is also inherited when
160 * not provided to the constructor. When using a {@code Thread.Builder} to create a
161 * platform thread, the daemon status, thread priority, and thread group are inherited
162 * when not set on the builder. As with the constructors, inheriting from the parent
163 * thread is done when the child {@code Thread} is created.
164 *
165 * <p> A {@code Thread} inherits its initial values of {@linkplain InheritableThreadLocal
166 * inheritable-thread-local} variables (including the context class loader) from
167 * the parent thread values at the time that the child {@code Thread} is created.
168 * The 5-param {@linkplain Thread#Thread(ThreadGroup, Runnable, String, long, boolean)
169 * constructor} can be used to create a thread that does not inherit its initial
170 * values from the constructing thread. When using a {@code Thread.Builder}, the
171 * {@link Builder#inheritInheritableThreadLocals(boolean) inheritInheritableThreadLocals}
172 * method can be used to select if the initial values are inherited.
173 *
174 * <p> Unless otherwise specified, passing a {@code null} argument to a constructor
175 * or method in this class will cause a {@link NullPointerException} to be thrown.
176 *
177 * @implNote
178 * In the JDK Reference Implementation, the virtual thread scheduler may be configured
179 * with the following system properties:
180 * <table class="striped">
181 * <caption style="display:none">System properties</caption>
182 * <thead>
183 * <tr>
184 * <th scope="col">System property</th>
185 * <th scope="col">Description</th>
186 * </tr>
187 * </thead>
188 * <tbody>
189 * <tr>
190 * <th scope="row">
191 * {@systemProperty jdk.virtualThreadScheduler.parallelism}
192 * </th>
193 * <td> The number of platform threads available for scheduling virtual
194 * threads. It defaults to the number of available processors. </td>
195 * </tr>
196 * <tr>
197 * <th scope="row">
198 * {@systemProperty jdk.virtualThreadScheduler.maxPoolSize}
199 * </th>
200 * <td> The maximum number of platform threads available to the scheduler.
201 * It defaults to 256. </td>
202 * </tr>
203 * </tbody>
204 * </table>
205 *
206 * @since 1.0
207 */
208 public class Thread implements Runnable {
209 /* Make sure registerNatives is the first thing <clinit> does. */
210 private static native void registerNatives();
211 static {
212 registerNatives();
213 }
214
215 /*
216 * Reserved for exclusive use by the JVM. Cannot be moved to the FieldHolder
217 * as it needs to be set by the VM for JNI attaching threads, before executing
218 * the constructor that will create the FieldHolder. The historically named
219 * `eetop` holds the address of the underlying VM JavaThread, and is set to
220 * non-zero when the thread is started, and reset to zero when the thread terminates.
227
228 // thread name
229 private volatile String name;
230
231 // interrupted status (read/written by VM)
232 volatile boolean interrupted;
233
234 // context ClassLoader
235 private volatile ClassLoader contextClassLoader;
236
237 // Additional fields for platform threads.
238 // All fields, except task and terminatingThreadLocals, are accessed directly by the VM.
239 private static class FieldHolder {
240 final ThreadGroup group;
241 final Runnable task;
242 final long stackSize;
243 volatile int priority;
244 volatile boolean daemon;
245 volatile int threadStatus;
246
247 // This map is maintained by the ThreadLocal class
248 ThreadLocal.ThreadLocalMap terminatingThreadLocals;
249
250 FieldHolder(ThreadGroup group,
251 Runnable task,
252 long stackSize,
253 int priority,
254 boolean daemon) {
255 this.group = group;
256 this.task = task;
257 this.stackSize = stackSize;
258 this.priority = priority;
259 if (daemon)
260 this.daemon = true;
261 }
262 }
263 private final FieldHolder holder;
264
265 ThreadLocal.ThreadLocalMap terminatingThreadLocals() {
266 return holder.terminatingThreadLocals;
267 }
268
269 void setTerminatingThreadLocals(ThreadLocal.ThreadLocalMap map) {
270 holder.terminatingThreadLocals = map;
271 }
272
273 /*
274 * ThreadLocal values pertaining to this thread. This map is maintained
275 * by the ThreadLocal class.
276 */
277 private ThreadLocal.ThreadLocalMap threadLocals;
278
279 ThreadLocal.ThreadLocalMap threadLocals() {
280 return threadLocals;
281 }
282
283 void setThreadLocals(ThreadLocal.ThreadLocalMap map) {
284 threadLocals = map;
285 }
286
287 /*
288 * InheritableThreadLocal values pertaining to this thread. This map is
289 * maintained by the InheritableThreadLocal class.
290 */
291 private ThreadLocal.ThreadLocalMap inheritableThreadLocals;
292
667 static {
668 U = Unsafe.getUnsafe();
669 NEXT_TID_OFFSET = Thread.getNextThreadIdOffset();
670 }
671 static long next() {
672 return U.getAndAddLong(null, NEXT_TID_OFFSET, 1);
673 }
674 }
675
676 /**
677 * Initializes a platform Thread.
678 *
679 * @param g the Thread group, can be null
680 * @param name the name of the new Thread
681 * @param characteristics thread characteristics
682 * @param task the object whose run() method gets called
683 * @param stackSize the desired stack size for the new thread, or
684 * zero to indicate that this parameter is to be ignored.
685 */
686 Thread(ThreadGroup g, String name, int characteristics, Runnable task, long stackSize) {
687
688 Thread parent = currentThread();
689 boolean attached = (parent == this); // primordial or JNI attached
690
691 if (attached) {
692 if (g == null) {
693 throw new InternalError("group cannot be null when attaching");
694 }
695 this.holder = new FieldHolder(g, task, stackSize, NORM_PRIORITY, false);
696 } else {
697 if (g == null) {
698 // default to current thread's group
699 g = parent.getThreadGroup();
700 }
701 int priority = Math.min(parent.getPriority(), g.getMaxPriority());
702 this.holder = new FieldHolder(g, task, stackSize, priority, parent.isDaemon());
703 }
704
705 if (attached && VM.initLevel() < 1) {
706 this.tid = PRIMORDIAL_TID; // primordial thread
707 } else {
751 }
752 this.contextClassLoader = parent.getContextClassLoader();
753 } else {
754 // default CCL to the system class loader when not inheriting
755 this.contextClassLoader = ClassLoader.getSystemClassLoader();
756 }
757
758 // special value to indicate this is a newly-created Thread
759 this.scopedValueBindings = NEW_THREAD_BINDINGS;
760
761 // create a FieldHolder object, needed when bound to an OS thread
762 if (bound) {
763 ThreadGroup g = Constants.VTHREAD_GROUP;
764 int pri = NORM_PRIORITY;
765 this.holder = new FieldHolder(g, null, -1, pri, true);
766 } else {
767 this.holder = null;
768 }
769 }
770
771 /**
772 * Returns a builder for creating a platform {@code Thread} or {@code ThreadFactory}
773 * that creates platform threads.
774 *
775 * @apiNote The following are examples using the builder:
776 * {@snippet :
777 * // Start a daemon thread to run a task
778 * Thread thread = Thread.ofPlatform().daemon().start(runnable);
779 *
780 * // Create an unstarted thread with name "duke", its start() method
781 * // must be invoked to schedule it to execute.
782 * Thread thread = Thread.ofPlatform().name("duke").unstarted(runnable);
783 *
784 * // A ThreadFactory that creates daemon threads named "worker-0", "worker-1", ...
785 * ThreadFactory factory = Thread.ofPlatform().daemon().name("worker-", 0).factory();
786 * }
787 *
788 * @return A builder for creating {@code Thread} or {@code ThreadFactory} objects.
789 * @since 21
790 */
1005 * that creates virtual threads.
1006 *
1007 * <p> Unless otherwise specified, passing a null argument to a method in
1008 * this interface causes a {@code NullPointerException} to be thrown.
1009 *
1010 * @see Thread#ofVirtual()
1011 * @since 21
1012 */
1013 sealed interface OfVirtual extends Builder
1014 permits ThreadBuilders.VirtualThreadBuilder {
1015
1016 @Override OfVirtual name(String name);
1017
1018 /**
1019 * @throws IllegalArgumentException {@inheritDoc}
1020 */
1021 @Override OfVirtual name(String prefix, long start);
1022
1023 @Override OfVirtual inheritInheritableThreadLocals(boolean inherit);
1024 @Override OfVirtual uncaughtExceptionHandler(UncaughtExceptionHandler ueh);
1025 }
1026 }
1027
1028 /**
1029 * Throws CloneNotSupportedException as a Thread can not be meaningfully
1030 * cloned. Construct a new Thread instead.
1031 *
1032 * @throws CloneNotSupportedException
1033 * always
1034 */
1035 @Override
1036 protected Object clone() throws CloneNotSupportedException {
1037 throw new CloneNotSupportedException();
1038 }
1039
1040 /**
1041 * Helper class for auto-numbering platform threads. The numbers start at
1042 * 0 and are separate from the thread identifier for historical reasons.
1043 */
1044 private static class ThreadNumbering {
1355 * the desired stack size for the new thread, or zero to indicate
1356 * that this parameter is to be ignored
1357 *
1358 * @param inheritInheritableThreadLocals
1359 * if {@code true}, inherit initial values for inheritable
1360 * thread-locals from the constructing thread, otherwise no initial
1361 * values are inherited
1362 *
1363 * @since 9
1364 * @see <a href="#inheritance">Inheritance when creating threads</a>
1365 */
1366 public Thread(ThreadGroup group, Runnable task, String name,
1367 long stackSize, boolean inheritInheritableThreadLocals) {
1368 this(group, checkName(name),
1369 (inheritInheritableThreadLocals ? 0 : NO_INHERIT_THREAD_LOCALS),
1370 task, stackSize);
1371 }
1372
1373 /**
1374 * Creates a virtual thread to execute a task and schedules it to execute.
1375 *
1376 * <p> This method is equivalent to:
1377 * <pre>{@code Thread.ofVirtual().start(task); }</pre>
1378 *
1379 * @param task the object to run when the thread executes
1380 * @return a new, and started, virtual thread
1381 * @see <a href="#inheritance">Inheritance when creating threads</a>
1382 * @since 21
1383 */
1384 public static Thread startVirtualThread(Runnable task) {
1385 Objects.requireNonNull(task);
1386 var thread = ThreadBuilders.newVirtualThread(null, null, 0, task);
1387 thread.start();
1388 return thread;
1389 }
1390
1391 /**
1392 * Returns {@code true} if this thread is a virtual thread. A virtual thread
1393 * is scheduled by the Java virtual machine rather than the operating system.
1394 *
|
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.Executor;
35 import java.util.concurrent.RejectedExecutionException;
36 import java.util.concurrent.ThreadFactory;
37 import java.util.concurrent.StructureViolationException;
38 import java.util.concurrent.locks.LockSupport;
39 import jdk.internal.event.ThreadSleepEvent;
40 import jdk.internal.javac.Restricted;
41 import jdk.internal.misc.TerminatingThreadLocal;
42 import jdk.internal.misc.Unsafe;
43 import jdk.internal.misc.VM;
44 import jdk.internal.reflect.CallerSensitive;
45 import jdk.internal.reflect.Reflection;
46 import jdk.internal.vm.Continuation;
47 import jdk.internal.vm.ScopedValueContainer;
48 import jdk.internal.vm.StackableScope;
49 import jdk.internal.vm.ThreadContainer;
50 import jdk.internal.vm.annotation.ForceInline;
51 import jdk.internal.vm.annotation.Hidden;
52 import jdk.internal.vm.annotation.IntrinsicCandidate;
53 import jdk.internal.vm.annotation.Stable;
54 import sun.nio.ch.Interruptible;
55
56 import static java.util.concurrent.TimeUnit.MILLISECONDS;
57 import static java.util.concurrent.TimeUnit.NANOSECONDS;
58
59 /**
60 * A <i>thread</i> is a thread of execution in a program. The Java
61 * virtual machine allows an application to have multiple threads of
62 * execution running concurrently.
63 *
64 * <p> {@code Thread} defines constructors and a {@link Builder} to create threads.
65 * {@linkplain #start() Starting} a thread schedules it to execute its {@link #run() run}
66 * method. The newly started thread executes concurrently with the thread that caused
67 * it to start.
68 *
69 * <p> A thread <i>terminates</i> if either its {@code run} method completes normally,
70 * or if its {@code run} method completes abruptly and the appropriate {@linkplain
71 * Thread.UncaughtExceptionHandler uncaught exception handler} completes normally or
72 * abruptly. With no code left to run, the thread has completed execution. The
73 * {@link #join() join} method can be used to wait for a thread to terminate.
74 *
75 * <p> Threads have a unique {@linkplain #threadId() identifier} and a {@linkplain
164 * status and thread priority from the parent thread at the time that the child {@code
165 * Thread} is created. The {@linkplain ThreadGroup thread group} is also inherited when
166 * not provided to the constructor. When using a {@code Thread.Builder} to create a
167 * platform thread, the daemon status, thread priority, and thread group are inherited
168 * when not set on the builder. As with the constructors, inheriting from the parent
169 * thread is done when the child {@code Thread} is created.
170 *
171 * <p> A {@code Thread} inherits its initial values of {@linkplain InheritableThreadLocal
172 * inheritable-thread-local} variables (including the context class loader) from
173 * the parent thread values at the time that the child {@code Thread} is created.
174 * The 5-param {@linkplain Thread#Thread(ThreadGroup, Runnable, String, long, boolean)
175 * constructor} can be used to create a thread that does not inherit its initial
176 * values from the constructing thread. When using a {@code Thread.Builder}, the
177 * {@link Builder#inheritInheritableThreadLocals(boolean) inheritInheritableThreadLocals}
178 * method can be used to select if the initial values are inherited.
179 *
180 * <p> Unless otherwise specified, passing a {@code null} argument to a constructor
181 * or method in this class will cause a {@link NullPointerException} to be thrown.
182 *
183 * @implNote
184 * In the JDK Reference Implementation, the following system properties may be used to
185 * configure the built-in default virtual thread scheduler:
186 * <table class="striped">
187 * <caption style="display:none">System properties</caption>
188 * <thead>
189 * <tr>
190 * <th scope="col">System property</th>
191 * <th scope="col">Description</th>
192 * </tr>
193 * </thead>
194 * <tbody>
195 * <tr>
196 * <th scope="row">
197 * {@systemProperty jdk.virtualThreadScheduler.parallelism}
198 * </th>
199 * <td> The default scheduler's target parallelism. It defaults to the number of
200 * available processors. </td>
201 * </tr>
202 * <tr>
203 * <th scope="row">
204 * {@systemProperty jdk.virtualThreadScheduler.maxPoolSize}
205 * </th>
206 * <td> The maximum number of platform threads available to the default scheduler.
207 * It defaults to 256. </td>
208 * </tr>
209 * </tbody>
210 * </table>
211 *
212 * @since 1.0
213 */
214 public class Thread implements Runnable {
215 /* Make sure registerNatives is the first thing <clinit> does. */
216 private static native void registerNatives();
217 static {
218 registerNatives();
219 }
220
221 /*
222 * Reserved for exclusive use by the JVM. Cannot be moved to the FieldHolder
223 * as it needs to be set by the VM for JNI attaching threads, before executing
224 * the constructor that will create the FieldHolder. The historically named
225 * `eetop` holds the address of the underlying VM JavaThread, and is set to
226 * non-zero when the thread is started, and reset to zero when the thread terminates.
233
234 // thread name
235 private volatile String name;
236
237 // interrupted status (read/written by VM)
238 volatile boolean interrupted;
239
240 // context ClassLoader
241 private volatile ClassLoader contextClassLoader;
242
243 // Additional fields for platform threads.
244 // All fields, except task and terminatingThreadLocals, are accessed directly by the VM.
245 private static class FieldHolder {
246 final ThreadGroup group;
247 final Runnable task;
248 final long stackSize;
249 volatile int priority;
250 volatile boolean daemon;
251 volatile int threadStatus;
252
253 // Used by NativeThread for signalling, set lazily, read from any thread
254 @Stable long nativeThreadID;
255
256 // This map is maintained by the ThreadLocal class
257 ThreadLocal.ThreadLocalMap terminatingThreadLocals;
258
259 FieldHolder(ThreadGroup group,
260 Runnable task,
261 long stackSize,
262 int priority,
263 boolean daemon) {
264 this.group = group;
265 this.task = task;
266 this.stackSize = stackSize;
267 this.priority = priority;
268 if (daemon)
269 this.daemon = true;
270 }
271 }
272 private final FieldHolder holder;
273
274 ThreadLocal.ThreadLocalMap terminatingThreadLocals() {
275 return holder.terminatingThreadLocals;
276 }
277
278 void setTerminatingThreadLocals(ThreadLocal.ThreadLocalMap map) {
279 holder.terminatingThreadLocals = map;
280 }
281
282 long nativeThreadID() {
283 return holder.nativeThreadID;
284 }
285
286 void setNativeThreadID(long id) {
287 holder.nativeThreadID = id;
288 }
289
290 /*
291 * ThreadLocal values pertaining to this thread. This map is maintained
292 * by the ThreadLocal class.
293 */
294 private ThreadLocal.ThreadLocalMap threadLocals;
295
296 ThreadLocal.ThreadLocalMap threadLocals() {
297 return threadLocals;
298 }
299
300 void setThreadLocals(ThreadLocal.ThreadLocalMap map) {
301 threadLocals = map;
302 }
303
304 /*
305 * InheritableThreadLocal values pertaining to this thread. This map is
306 * maintained by the InheritableThreadLocal class.
307 */
308 private ThreadLocal.ThreadLocalMap inheritableThreadLocals;
309
684 static {
685 U = Unsafe.getUnsafe();
686 NEXT_TID_OFFSET = Thread.getNextThreadIdOffset();
687 }
688 static long next() {
689 return U.getAndAddLong(null, NEXT_TID_OFFSET, 1);
690 }
691 }
692
693 /**
694 * Initializes a platform Thread.
695 *
696 * @param g the Thread group, can be null
697 * @param name the name of the new Thread
698 * @param characteristics thread characteristics
699 * @param task the object whose run() method gets called
700 * @param stackSize the desired stack size for the new thread, or
701 * zero to indicate that this parameter is to be ignored.
702 */
703 Thread(ThreadGroup g, String name, int characteristics, Runnable task, long stackSize) {
704 Thread parent = currentThread();
705 boolean attached = (parent == this); // primordial or JNI attached
706
707 if (attached) {
708 if (g == null) {
709 throw new InternalError("group cannot be null when attaching");
710 }
711 this.holder = new FieldHolder(g, task, stackSize, NORM_PRIORITY, false);
712 } else {
713 if (g == null) {
714 // default to current thread's group
715 g = parent.getThreadGroup();
716 }
717 int priority = Math.min(parent.getPriority(), g.getMaxPriority());
718 this.holder = new FieldHolder(g, task, stackSize, priority, parent.isDaemon());
719 }
720
721 if (attached && VM.initLevel() < 1) {
722 this.tid = PRIMORDIAL_TID; // primordial thread
723 } else {
767 }
768 this.contextClassLoader = parent.getContextClassLoader();
769 } else {
770 // default CCL to the system class loader when not inheriting
771 this.contextClassLoader = ClassLoader.getSystemClassLoader();
772 }
773
774 // special value to indicate this is a newly-created Thread
775 this.scopedValueBindings = NEW_THREAD_BINDINGS;
776
777 // create a FieldHolder object, needed when bound to an OS thread
778 if (bound) {
779 ThreadGroup g = Constants.VTHREAD_GROUP;
780 int pri = NORM_PRIORITY;
781 this.holder = new FieldHolder(g, null, -1, pri, true);
782 } else {
783 this.holder = null;
784 }
785 }
786
787 /**
788 * The task that a {@linkplain VirtualThreadScheduler virtual thread scheduler}
789 * executes on a platform thread to
790 * {@linkplain VirtualThreadScheduler#onStart(VirtualThreadTask) start}
791 * or {@linkplain VirtualThreadScheduler#onContinue(VirtualThreadTask) continue}
792 * execution of a virtual thread. While executing the task, the platform thread is
793 * the virtual thread's <em>carrier</em>.
794 *
795 * <p> There is a {@code VirtualThreadTask} object for each virtual thread. The
796 * scheduler arranges to execute its {@link #run()} method when called to start or
797 * continue the virtual thread. A scheduler may attach an object to the task.
798 *
799 * @since 99
800 */
801 public sealed interface VirtualThreadTask extends Runnable permits
802 VirtualThread.BuiltinSchedulerTask, VirtualThread.CustomSchedulerTask {
803
804 /**
805 * {@return the virtual thread that this task starts or continues}
806 */
807 Thread thread();
808
809 /**
810 * Runs the task on the current thread as the carrier thread.
811 *
812 * <p> Invoking this method with the interrupted status set will first
813 * clear the interrupt status. Interrupting the carrier thread while
814 * running the task leads to unspecified behavior.
815 *
816 * @throws IllegalStateException if the virtual thread is not in a state to
817 * run on the current thread
818 * @throws IllegalCallerException if the current thread is a virtual thread
819 */
820 @Override
821 void run();
822
823 /**
824 * Attaches the given object to this task.
825 * @param att the object to attach
826 * @return the previously-attached object, if any, otherwise {@code null}
827 */
828 Object attach(Object att);
829
830 /**
831 * Retrieves the current attachment.
832 * @return the object currently attached to this task or {@code null} if
833 * there is no attachment
834 */
835 Object attachment();
836 }
837
838 /**
839 * Virtual thread scheduler.
840 *
841 * @apiNote The following example creates a virtual thread scheduler that uses a small
842 * set of platform threads.
843 * {@snippet lang=java :
844 * ExecutorService threadPool = Executors.newFixedThreadPool(4);
845 * var scheduler = new VirtualThreadScheduler() {
846 * private void submit(VirtualThreadTask task) {
847 * Thread caller = Thread.currentThread();
848 * threadPool.submit(() -> {
849 * Thread vthread = task.thread();
850 * Thread carrier = Thread.currentThread();
851 * try {
852 * task.run();
853 * } finally {
854 * assert Thread.currentThread() == carrier;
855 * boolean terminated = !vthread.isAlive();
856 * }
857 * });
858 * }
859 * @Override
860 * public void onStart(VirtualThreadTask task) {
861 * submit(task);
862 * }
863 * @Override
864 * public void onContinue(VirtualThreadTask task) {
865 * submit(task);
866 * }
867 * };
868 * }
869 *
870 * <p> Unless otherwise specified, passing a null argument to a method in
871 * this interface causes a {@code NullPointerException} to be thrown.
872 *
873 * @see Builder.OfVirtual#scheduler(VirtualThreadScheduler)
874 * @since 99
875 * @see VirtualThreadScheduler
876 */
877 public interface VirtualThreadScheduler {
878 /**
879 * Invoked by {@link Thread#start()} to start execution of a {@linkplain
880 * VirtualThreadTask#thread() virtual thread}.
881 * The scheduler's implementation of this method must arrange to execute the
882 * given task's {@link VirtualThreadTask#run() run()} method on a platform thread.
883 *
884 * @implNote If invoked from a virtual thread, then the caller virtual thread is
885 * <em>pinned</em> to its carrier while executing the {@code onStart} method.
886 *
887 * @param task the task to execute
888 * @throws RejectedExecutionException if the scheduler cannot accept the task
889 */
890 void onStart(VirtualThreadTask task);
891
892 /**
893 * Invoked to continue execution of a {@linkplain VirtualThreadTask#thread()
894 * virtual thread}.
895 * The scheduler's implementation of this method must arrange to execute the
896 * given task's {@link VirtualThreadTask#run() run()} method on a platform thread.
897 *
898 * @implNote If invoked from a virtual thread, then the caller virtual thread is
899 * <em>pinned</em> to its carrier while executing the {@code onContinue} method.
900 *
901 * @param task the task to execute
902 * @throws RejectedExecutionException if the scheduler cannot accept the task
903 */
904 void onContinue(VirtualThreadTask task);
905
906 /**
907 * {@return a virtual thread scheduler that delegates tasks to the given executor}
908 * @param executor the executor
909 */
910 static VirtualThreadScheduler adapt(Executor executor) {
911 Objects.requireNonNull(executor);
912 return new VirtualThreadScheduler() {
913 @Override
914 public void onStart(VirtualThreadTask task) {
915 executor.execute(task);
916 }
917 @Override
918 public void onContinue(VirtualThreadTask task) {
919 executor.execute(task);
920 }
921 };
922 }
923
924 /**
925 * {@return the virtual thread scheduler for the current virtual thread}
926 * @throws UnsupportedOperationException if the current thread is not a virtual
927 * thread or scheduling virtual threads to a user-provided scheduler is not
928 * supported by this VM
929 */
930 @CallerSensitive
931 @Restricted
932 static VirtualThreadScheduler current() {
933 Class<?> caller = Reflection.getCallerClass();
934 caller.getModule().ensureNativeAccess(VirtualThreadScheduler.class,
935 "current",
936 caller,
937 false);
938 if (Thread.currentThread() instanceof VirtualThread vthread) {
939 return vthread.scheduler(false);
940 } else {
941 throw new UnsupportedOperationException();
942 }
943 }
944 }
945
946 /**
947 * Returns a builder for creating a platform {@code Thread} or {@code ThreadFactory}
948 * that creates platform threads.
949 *
950 * @apiNote The following are examples using the builder:
951 * {@snippet :
952 * // Start a daemon thread to run a task
953 * Thread thread = Thread.ofPlatform().daemon().start(runnable);
954 *
955 * // Create an unstarted thread with name "duke", its start() method
956 * // must be invoked to schedule it to execute.
957 * Thread thread = Thread.ofPlatform().name("duke").unstarted(runnable);
958 *
959 * // A ThreadFactory that creates daemon threads named "worker-0", "worker-1", ...
960 * ThreadFactory factory = Thread.ofPlatform().daemon().name("worker-", 0).factory();
961 * }
962 *
963 * @return A builder for creating {@code Thread} or {@code ThreadFactory} objects.
964 * @since 21
965 */
1180 * that creates virtual threads.
1181 *
1182 * <p> Unless otherwise specified, passing a null argument to a method in
1183 * this interface causes a {@code NullPointerException} to be thrown.
1184 *
1185 * @see Thread#ofVirtual()
1186 * @since 21
1187 */
1188 sealed interface OfVirtual extends Builder
1189 permits ThreadBuilders.VirtualThreadBuilder {
1190
1191 @Override OfVirtual name(String name);
1192
1193 /**
1194 * @throws IllegalArgumentException {@inheritDoc}
1195 */
1196 @Override OfVirtual name(String prefix, long start);
1197
1198 @Override OfVirtual inheritInheritableThreadLocals(boolean inherit);
1199 @Override OfVirtual uncaughtExceptionHandler(UncaughtExceptionHandler ueh);
1200
1201 /**
1202 * Sets the scheduler.
1203 *
1204 * <p> The virtual thread will be scheduled by the Java virtual machine with
1205 * the given scheduler. The scheduler's {@link
1206 * VirtualThreadScheduler#onStart(VirtualThreadTask) onStart} and
1207 * {@link VirtualThreadScheduler#onContinue(VirtualThreadTask) onContinue}
1208 * methods may be invoked in the context of a virtual thread. The scheduler
1209 * must arrange to execute the {@link VirtualThreadTask}'s
1210 * {@code run} method on a platform thread. Attempting to execute the run
1211 * method in a virtual thread causes {@link WrongThreadException} to be thrown.
1212 * The {@code onStart} and {@code onContinue }methods may be invoked at
1213 * sensitive times (e.g. when unparking a thread) so care should be taken to
1214 * not directly execute the task on the <em>current thread</em>.
1215 *
1216 * @param scheduler the scheduler
1217 * @return this builder
1218 * @throws UnsupportedOperationException if scheduling virtual threads to a
1219 * user-provided scheduler is not supported by this VM
1220 *
1221 * @since 99
1222 */
1223 @CallerSensitive
1224 @Restricted
1225 OfVirtual scheduler(VirtualThreadScheduler scheduler);
1226 }
1227 }
1228
1229 /**
1230 * Throws CloneNotSupportedException as a Thread can not be meaningfully
1231 * cloned. Construct a new Thread instead.
1232 *
1233 * @throws CloneNotSupportedException
1234 * always
1235 */
1236 @Override
1237 protected Object clone() throws CloneNotSupportedException {
1238 throw new CloneNotSupportedException();
1239 }
1240
1241 /**
1242 * Helper class for auto-numbering platform threads. The numbers start at
1243 * 0 and are separate from the thread identifier for historical reasons.
1244 */
1245 private static class ThreadNumbering {
1556 * the desired stack size for the new thread, or zero to indicate
1557 * that this parameter is to be ignored
1558 *
1559 * @param inheritInheritableThreadLocals
1560 * if {@code true}, inherit initial values for inheritable
1561 * thread-locals from the constructing thread, otherwise no initial
1562 * values are inherited
1563 *
1564 * @since 9
1565 * @see <a href="#inheritance">Inheritance when creating threads</a>
1566 */
1567 public Thread(ThreadGroup group, Runnable task, String name,
1568 long stackSize, boolean inheritInheritableThreadLocals) {
1569 this(group, checkName(name),
1570 (inheritInheritableThreadLocals ? 0 : NO_INHERIT_THREAD_LOCALS),
1571 task, stackSize);
1572 }
1573
1574 /**
1575 * Creates a virtual thread to execute a task and schedules it to execute.
1576 * The thread is scheduled by the default virtual thread scheduler.
1577 *
1578 * <p> This method is equivalent to:
1579 * <pre>{@code Thread.ofVirtual().start(task); }</pre>
1580 *
1581 * @param task the object to run when the thread executes
1582 * @return a new, and started, virtual thread
1583 * @see <a href="#inheritance">Inheritance when creating threads</a>
1584 * @since 21
1585 */
1586 public static Thread startVirtualThread(Runnable task) {
1587 Objects.requireNonNull(task);
1588 var thread = ThreadBuilders.newVirtualThread(null, null, 0, task);
1589 thread.start();
1590 return thread;
1591 }
1592
1593 /**
1594 * Returns {@code true} if this thread is a virtual thread. A virtual thread
1595 * is scheduled by the Java virtual machine rather than the operating system.
1596 *
|