Class VirtualThread
A thread of control that is not an OS thread.
One of these per connection is what lets a server keep a context per client without keeping an OS THREAD per client. The difference is not stylistic: a handoff between OS threads measured 21181ns on the machine this was built on, and switching a virtual thread measured 2.6ns.
A virtual thread runs until it finishes or until it asks for bytes that have not arrived, at which point it parks and the host thread goes and runs another one. Parking happens inside the ordinary blocking calls, so the code a virtual thread runs is written in the plain blocking style and does not know it is not a thread -- which is the reason to have them rather than callbacks.
-
Field Summary
FieldsModifier and TypeFieldDescriptionstatic final intresume(long): the connection is done and the handle should be freed.static final intresume(long): waiting for bytes; its descriptor goes back to the poller.static final intresume(long): it gave up its turn but is ready to run again NOW.static final intresume(long): parked on an OUTBOUND descriptor -- a database socket, a TLS peer, an HTTP call -- rather than on its own. -
Method Summary
Modifier and TypeMethodDescriptionstatic longcreate(int fd, int stackBytes) A virtual thread that will servefdwhen first resumed.static longcreateTask(long token, int stackBytes) A virtual thread that runs a background task: when first resumed it callsTasks.runVirtual(token).static longcurrent()The handle of the virtual thread the caller runs on, or 0 on a host or platform thread.static intdescriptorOf(long handle) The descriptor this virtual thread serves, or -1.static voidfree(long handle) Release it.static booleanWhether the caller is running on a virtual thread rather than a host thread.static voidreport()Print created/finished/freed counts to stderr, for diagnosis.static intresume(long handle) Run it until it parks, yields or finishes.static booleanWhether this build has virtual threads at all, which is not the same question as isVirtual().static intwaitCount(long handle) How many descriptors a virtual thread that answeredWAITINGwaits on; 0 for none, which is a wait on the timeout alone.static intwaitDescriptor(long handle, int index) Theindex-th descriptor aWAITINGvirtual thread waits on.static intwaitEvents(long handle, int index) What it waits for on that descriptor:Reactor.READ,Reactor.WRITEor both.static longwaitTimeout(long handle) How long it is willing to wait, in milliseconds from now, or -1 for no bound.static voidyieldNow()Step aside so the host thread can run another virtual thread, without waiting for anything.
-
Field Details
-
FINISHED
public static final int FINISHEDresume(long): the connection is done and the handle should be freed.- See Also:
-
PARKED_IO
public static final int PARKED_IOresume(long): waiting for bytes; its descriptor goes back to the poller.- See Also:
-
RUNNABLE
public static final int RUNNABLEresume(long): it gave up its turn but is ready to run again NOW.It is waiting on something that is not its socket -- the collector's allocation backpressure, or its own fairness yield. Putting it on the poller instead would wait for a client that is waiting for the response this virtual thread owes it, and the connection would hang for ever.
- See Also:
-
WAITING
public static final int WAITINGresume(long): parked on an OUTBOUND descriptor -- a database socket, a TLS peer, an HTTP call -- rather than on its own. The host registers the descriptorswaitCount(long)names with its poller and resumes it when one is ready orwaitTimeout(long)runs out, running other virtual threads meanwhile.- See Also:
-
-
Method Details
-
create
public static long create(int fd, int stackBytes) A virtual thread that will serve
fdwhen first resumed.The stack is the C stack only. Java locals and the operand stack live in the virtual thread's own VM state, which is mapped lazily, so what this size buys is call DEPTH rather than data: it holds the C activation records of the Java methods the connection is nested inside.
- Returns:
- a handle, or 0 if the stack could not be allocated
-
createTask
public static long createTask(long token, int stackBytes) A virtual thread that runs a background task: when first resumed it calls
Tasks.runVirtual(token). It has no descriptor --descriptorOf(long)answers -1 -- so its host runs it from the ring and never parks it on the poller.Returns
a handle, or 0 if the stack could not be allocated
-
resume
public static int resume(long handle) Run it until it parks, yields or finishes. One of the four constants. -
waitCount
public static int waitCount(long handle) How many descriptors a virtual thread that answeredWAITINGwaits on; 0 for none, which is a wait on the timeout alone. -
waitDescriptor
public static int waitDescriptor(long handle, int index) Theindex-th descriptor aWAITINGvirtual thread waits on. -
waitEvents
public static int waitEvents(long handle, int index) What it waits for on that descriptor:Reactor.READ,Reactor.WRITEor both. -
waitTimeout
public static long waitTimeout(long handle) How long it is willing to wait, in milliseconds from now, or -1 for no bound. -
descriptorOf
public static int descriptorOf(long handle) The descriptor this virtual thread serves, or -1. -
free
public static void free(long handle) Release it. Only valid onceresume(long)has returned FINISHED. -
yieldNow
public static void yieldNow()Step aside so the host thread can run another virtual thread, without waiting for anything.
Parking happens by itself when bytes have not arrived. This is for the other case: a virtual thread that COULD keep going but has had its turn. A no-op when the caller is not a virtual thread.
-
current
public static long current()The handle of the virtual thread the caller runs on, or 0 on a host or platform thread. What a waiter hands its host so it can nap rather than be resumed again at once. -
isVirtual
public static boolean isVirtual()Whether the caller is running on a virtual thread rather than a host thread. -
supported
public static boolean supported()Whether this build has virtual threads at all, which is not the same question as isVirtual(). The context switch is compiled in only on non-Windows aarch64/x86_64; elsewhere create() can only ever return 0. The server asks this to pick its default poll mode. -
report
public static void report()Print created/finished/freed counts to stderr, for diagnosis.
-