Detecting Virtual Thread Pinning in Java

Virtual threads represent a significant leap forward for Java. I believe they will rejuvenate the language. Combined with all the recent advancements, this will further solidify Java's dominance in areas where it already leads, such as enterprise software.
I was aware that Java 21 had issues with thread pinning when entering a synchronized block. To verify whether this problem has been resolved in Java 24, I needed a way of knowing if a thread is pinned and used the following jvm flag: -Djdk.tracePinnedThreads=full
This flag should help track if virtual threads still get pinned.
For testing purposes, we have this basic code:
private static final Object lock = new Object();
public static void main(String[] args) {
Thread virtualThread = Thread.ofVirtual().start(() -> {
synchronized (lock) {
System.out.println("vt");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
});
}
When running it with Java 21, I got the following log:
Virtual thread is pinned inside synchronized block
Thread[#22,ForkJoinPool-1-worker-1,5,CarrierThreads]
java.base/java.lang.VirtualThread$VThreadContinuation.onPinned(VirtualThread.java:183)
java.base/jdk.internal.vm.Continuation.onPinned0(Continuation.java:393)
java.base/java.lang.VirtualThread.parkNanos(VirtualThread.java:621)
java.base/java.lang.VirtualThread.sleepNanos(VirtualThread.java:791)
java.base/java.lang.Thread.sleep(Thread.java:507)
playground.thread.Echo.lambda$main$0(Echo.java:21) <== monitors:1
java.base/java.lang.VirtualThread.run(VirtualThread.java:309)
When running the same code with Java 24, no pinning occurs. While I understand it can still happen when calling native code, for most use cases the issue is gone.
Subscribe to my newsletter
Read articles from Liviu Stirb directly inside your inbox. Subscribe to the newsletter, and don't miss out.
Written by
