Class VirtualThread

java.lang.Object
com.codename1.backend.VirtualThread

public final class VirtualThread extends Object

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

    Fields
    Modifier and Type
    Field
    Description
    static final int
    resume(long): the connection is done and the handle should be freed.
    static final int
    resume(long): waiting for bytes; its descriptor goes back to the poller.
    static final int
    resume(long): it gave up its turn but is ready to run again NOW.
    static final int
    resume(long): parked on an OUTBOUND descriptor -- a database socket, a TLS peer, an HTTP call -- rather than on its own.
  • Method Summary

    Modifier and Type
    Method
    Description
    static long
    create(int fd, int stackBytes)
    A virtual thread that will serve fd when first resumed.
    static long
    createTask(long token, int stackBytes)
    A virtual thread that runs a background task: when first resumed it calls Tasks.runVirtual(token).
    static long
    The handle of the virtual thread the caller runs on, or 0 on a host or platform thread.
    static int
    descriptorOf(long handle)
    The descriptor this virtual thread serves, or -1.
    static void
    free(long handle)
    Release it.
    static boolean
    Whether the caller is running on a virtual thread rather than a host thread.
    static void
    Print created/finished/freed counts to stderr, for diagnosis.
    static int
    resume(long handle)
    Run it until it parks, yields or finishes.
    static boolean
    Whether this build has virtual threads at all, which is not the same question as isVirtual().
    static int
    waitCount(long handle)
    How many descriptors a virtual thread that answered WAITING waits on; 0 for none, which is a wait on the timeout alone.
    static int
    waitDescriptor(long handle, int index)
    The index-th descriptor a WAITING virtual thread waits on.
    static int
    waitEvents(long handle, int index)
    What it waits for on that descriptor: Reactor.READ, Reactor.WRITE or both.
    static long
    waitTimeout(long handle)
    How long it is willing to wait, in milliseconds from now, or -1 for no bound.
    static void
    Step aside so the host thread can run another virtual thread, without waiting for anything.

    Methods inherited from class Object

    clone, equals, getClass, hashCode, notify, notifyAll, toString, wait, wait, wait
  • Field Details

    • FINISHED

      public static final int FINISHED
      resume(long): the connection is done and the handle should be freed.
      See Also:
    • PARKED_IO

      public static final int PARKED_IO
      resume(long): waiting for bytes; its descriptor goes back to the poller.
      See Also:
    • RUNNABLE

      public static final int RUNNABLE

      resume(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 WAITING
      resume(long): parked on an OUTBOUND descriptor -- a database socket, a TLS peer, an HTTP call -- rather than on its own. The host registers the descriptors waitCount(long) names with its poller and resumes it when one is ready or waitTimeout(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 fd when 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 answered WAITING waits on; 0 for none, which is a wait on the timeout alone.
    • waitDescriptor

      public static int waitDescriptor(long handle, int index)
      The index-th descriptor a WAITING virtual thread waits on.
    • waitEvents

      public static int waitEvents(long handle, int index)
      What it waits for on that descriptor: Reactor.READ, Reactor.WRITE or 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 once resume(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.