I am an enthusiast and am wondering about virtual threads. In the docs it says that one of the conditions to pin the thread is in a synchronized block, and in those cases to use a semaphore. Here are the docs to the JEP https://openjdk.org/jeps/444
There are two scenarios in which a virtual thread cannot be unmounted during blocking operations because it is pinned to its carrier: When it executes code inside a synchronized block or method, or When it executes a native method or a foreign function.
Is this due to the implementation of a synchronized block being a spin lock and the thread does not stop executing instructions, while a semaphore will yield after a few attempts?
The JEP 425 gives, in my opinion, more detailed technical information on the issue you raised. It mentions java.util.concurrent.locks.ReentrantLock
. A synchronization primitive Semaphore
also exists in Java Concurrency and it uses the same AbstractQueuedSynchronizer
a.k.a. the AQS as ReentrantLock
does, so it is conceptually the same, but semantic of ReentrantLock
is very similar to that of synchronized
block, which is advised to be replaced. But this is a technical remark.
The key difference is that ReentrantLock
, AQS, direct Unsafe
/VarHandle
and similar synchronization primitives use non-blocking CAS technique while synchronized
blocks the thread, at least in a case of contention.
To understand the difference between the two, I'd advise to learn more about CAS and/or experiment with Java Atomic*
methods compareAndSet
.
As a side note, ReentrantLock
, AQS and few other other synchronization primitives still may block the thread (in fact, it is necessary, generally speaking), it is done by calling LockSupport.park
methods. Under the hood, LockSupport.park
also invokes a native method, but for some reason this is not (or lesser?) problem for Virtual Threads.