java virtual thread

发布时间 2023-04-04 16:45:27作者: ploolq

A virtual thread is an instance of java.lang.Thread that is not tied to a particular OS thread.

A platform thread, by contrast, is an instance of java.lang.
Thread implemented in the traditional way, as a thin wrapper around an OS thread.

Application code in the thread-per-request style can run in a virtual thread for the entire duration of a request,
but the virtual thread consumes an OS thread only while it performs calculations on the CPU.
The result is the same scalability as the asynchronous style, except it is achieved transparently:
When code running in a virtual thread calls a blocking I/O operation in the java.* API,
the runtime performs a non-blocking OS call and automatically suspends the virtual thread until it can be resumed later.

To Java developers, virtual threads are simply threads that are cheap to create and almost infinitely plentiful.
Hardware utilization is close to optimal, allowing a high level of concurrency and, as a result,
high throughput, while the application remains harmonious with the multithreaded design of the Java Platform and its tooling.

light weight

Virtual threads are cheap and plentiful, and thus should never be pooled:
A new virtual thread should be created for every application task.
Most virtual threads will thus be short-lived and have shallow call stacks,
performing as little as a single HTTP client call or a single JDBC query.

Platform threads, by contrast, are heavyweight and expensive, and thus often must be pooled.
They tend to be long-lived, have deep call stacks, and be shared among many tasks.

Scheduler

The JDK's virtual thread scheduler is a work-stealing ForkJoinPool that operates in FIFO mode.
The parallelism of the scheduler is the number of platform threads available for the purpose of scheduling virtual threads.
By default it is equal to the number of available processors, but it can be tuned with the system property jdk.virtualThreadScheduler.

Execution

To take advantage of virtual threads, it is not necessary to rewrite your program.
Virtual threads do not require or expect application code to explicitly hand back control to the scheduler;
in other words, virtual threads are not cooperative.

User code must not make assumptions about how or when virtual threads are
assigned to platform threads any more than it makes assumptions about how or
when platform threads are assigned to processor cores.

To run code in a virtual thread, the JDK's virtual thread scheduler assigns the virtual thread for execution on a platform thread by mounting the virtual thread on a platform thread.
This makes the platform thread become the carrier of the virtual thread.

Later, after running some code, the virtual thread can unmount from its carrier.
At that point the platform thread is free so the scheduler can mount a different virtual thread on it, thereby making it a carrier again.

Typically, a virtual thread will unmount when it blocks on I/O or some other blocking operation in the JDK, such as BlockingQueue.take().
When the blocking operation is ready to complete (e.g., bytes have been received on a socket),
it submits the virtual thread back to the scheduler, which will mount the virtual thread on a carrier to resume execution.

The mounting and unmounting of virtual threads happens frequently and transparently, and without blocking any OS threads.

For example, the server application shown earlier included the following line of code, which contains calls to blocking operations:

response.send(future1.get() + future2.get());

These operations will cause the virtual thread to mount and unmount multiple times,
typically once for each call to get() and possibly multiple times in the course of performing I/O in send(...).

The vast majority of blocking operations in the JDK will unmount the virtual thread, freeing its carrier and the underlying OS thread to take on new work.

However, some blocking operations in the JDK do not unmount the virtual thread,
and thus block both its carrier and the underlying OS thread.

This is because of limitations either at the OS level (e.g., many filesystem operations) or at the JDK level (e.g., Object.wait()).
The implementation of these blocking operations will compensate for the capture of the OS thread by temporarily expanding the parallelism of the scheduler. (OS 不支持阻塞等待 fs 操作,开启更多线程,类似于 node.js 读取文件使用 worker thread)

Consequently, the number of platform threads in the scheduler's ForkJoinPool may temporarily exceed the number of available processors.
The maximum number of platform threads available to the scheduler can be tuned with the system property jdk.virtualThreadScheduler.maxPoolSize.

https://openjdk.org/jeps/425

问题

virtual thread level sync primitive

比如mutex, atomic 等,

以组织virtual thread task graph。

jdk 中 是否有支持?