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 primitiveSemaphore
also exists in Java Concurrency and it uses the sameAbstractQueuedSynchronizer
a.k.a. the AQS asReentrantLock
does, so it is conceptually the same, but semantic ofReentrantLock
is very similar to that ofsynchronized
block, which is advised to be replaced. But this is a technical remark.The key difference is that
ReentrantLock
, AQS, directUnsafe
/VarHandle
and similar synchronization primitives use non-blocking CAS technique whilesynchronized
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*
methodscompareAndSet
.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 callingLockSupport.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.