How does a Java virtual thread know when the thread is waiting?

2.1k Views Asked by At

When a virtual thread is blocked due to synchronized call, it's yielding, so the scheduler will unmount it from related Carrier thread.

I was wondering, how does a virtual thread know that it's currently at wait state and it's time to yield?

2

There are 2 best solutions below

1
On

At appropriate places in the code, the blocking is detected. For example

  public static void parkNanos(Object blocker, long nanos) {
        if (nanos > 0) {
            Thread t = Thread.currentThread();
            setBlocker(t, blocker);
            try {
                if (t.isVirtual()) {
                    VirtualThreads.park(nanos);<====
                } else {
                    U.park(false, nanos);
                }
            } finally {
                setBlocker(t, null);
            }
        }
    }
5
On

It appears that you have a slight misconception: When a virtual thread is blocked due to synchronization, it is in fact yielding, but the scheduler will not unmount it from the related carrier thread. Instead, the carrier thread will be blocked, yielding. This is one of the current shortcomings of Project Loom, and it is well documented. The team says they might fix it in the future.

Specifically, in Coming to Java 19: Virtual threads and platform threads by Nicolai Parlog 2022-05 we read:

Unfortunately, there’s one more imperfection in the initial virtual thread proposal: When a virtual thread executes a native method or a foreign function or it executes code inside a synchronized block or method, the virtual thread will be pinned to its carrier thread. A pinned thread will not unmount in situations where it otherwise would.

(Emphasis mine.)

Further down in the same article, we read:

[...] a good alternative to synchronization is a ReentrantLock.

Note that I have read the same things in a number of other official sources of information, not just from the above blog post.

This means that at least for now, if you want to avoid blocking the carrier thread, you must refrain from using the synchronized keyword; instead, you must use a ReentrantLock or some other runtime library class that blocks waiting for something to happen while yielding, such as CountdownLatch etc.

So, to answer your question of "how does a Java virtual thread know when the thread is waiting?" the answer is that all the classes that provide block waiting while yielding (even the Sleep() method of Thread) have been modified in Java 19 so that they now co-operate with the virtual threads mechanism precisely so as to allow unmounting from the carrier thread.