Virtual Thread Pinned By Synchronized Code
ID |
java.virtual_thread_runs_synchronized_code |
Severity |
low |
Remediation Complexity |
medium |
Remediation Risk |
low |
Remediation Effort |
medium |
Resource |
Efficiency |
Language |
Java |
Tags |
efficiency |
Description
Applies only to Java 21, 22 and 23. Since Java 24, virtual threads are no longer pinned by
synchronized code, and this finding does not apply.
Reports Thread.startVirtualThread(task) or Thread.ofVirtual()….start(task) where task’s
body contains a `synchronized block, or calls a method the project resolves as synchronized.
A platform thread (new Thread(…)) doing the same thing, and a task submitted to any other
executor (including a custom ThreadPoolExecutor), are out of scope.
Rationale
On Java 21 through 23, code running inside a synchronized block or method pins the virtual
thread to its underlying carrier OS thread for as long as the block is active: the thread cannot
be unmounted even for a blocking operation inside it. That defeats the scalability benefit
virtual threads exist to provide — many virtual threads sharing a small pool of OS threads — and
can turn a blocking call inside a synchronized section into a bottleneck on the carrier pool.
Thread.startVirtualThread(() -> {
synchronized (lock) {
blockingCall(); // pins the carrier thread on Java 21-23
}
});