Java Virtual Threads: Boost Performance, Fix Pin Issues, and Migrate Easily
This article explains the evolution of Java virtual threads in AJDK, details performance improvements, examines pinning problems caused by synchronization and native code, provides migration steps, configuration tips, and code examples, and introduces diagnostic tools for troubleshooting virtual thread issues.
Basic Introduction
Java virtual threads (also called fibers or coroutines) originated from the Loom project and have been integrated into AJDK21.0.5, replacing the earlier wisp implementation. They aim to simplify high‑concurrency programming by reducing the cost of thread creation and context switching.
Performance Reference
Stability tests during a large‑scale rollout showed no issues, and performance benchmarks compare AJDK21 without coroutines, AJDK21 with virtual threads, AJDK11, and AJDK11 with wisp enabled.
Using Virtual Threads
Developers can replace traditional threads with virtual threads by changing thread creation code. For example:
<span>// Traditional Java thread</span>
Thread javaThread = new Thread(() -> {
// some tasks
});
<span>// Lightweight virtual thread</span>
Thread virtualThread = Thread.ofVirtual().start(() -> {
// some tasks
});Thread pools can be converted to virtual thread pools by using Thread.ofVirtual().factory() or the recommended per‑task executor:
<span>// Recommended per‑task virtual thread executor</span>
ExecutorService es = Executors.newVirtualThreadPerTaskExecutor();
<span>// Traditional thread pool adapted to virtual threads</span>
ThreadFactory factory = Thread.ofVirtual().factory();
ExecutorService executorService = new ThreadPoolExecutor(
MAX_WORKER_THREADS, MAX_WORKER_THREADS,
10L, TimeUnit.MINUTES,
new LinkedBlockingQueue<Runnable>(),
factory);Important Parameters
Two core JVM parameters control virtual thread scheduling: -Djdk.virtualThreadScheduler.parallelism=N – sets the number of carrier threads (usually equal to CPU cores). -Djdk.virtualThreadScheduler.maxPoolSize=M – maximum number of carrier threads; a larger value helps mitigate pinning issues.
Additional parameters such as -Djdk.virtualThreadScheduler.minRunnable are also available.
Not Recommended Practices
Manually creating a virtual‑thread factory without using the provided APIs can lead to crashes or deadlocks because the necessary VM classes and objects may not be pre‑initialized.
public static void main(String[] args) {
ForkJoinPool.ForkJoinWorkerThreadFactory forkJoinWorkerThreadFactory = new ForkJoinPool.ForkJoinWorkerThreadFactory() {
@Override
public ForkJoinWorkerThread newThread(ForkJoinPool pool) {
return new CarrierThread(pool);
}
};
ForkJoinPool scheduler = new ForkJoinPool(4, forkJoinWorkerThreadFactory, (t, e) -> {}, true,
4, 10, 1, pool -> true, 30, TimeUnit.SECONDS);
Thread.Builder builder = virtualThreadBuilder(scheduler);
builder.start(() -> {});
ExecutorService es = Executors.newThreadPerTaskExecutor(builder.factory());
}Virtual Thread Pin Problems and AJDK Solutions
Pinning occurs when a virtual thread cannot be detached from its carrier thread, causing the carrier to be occupied indefinitely. Common causes include class loading, synchronized blocks, and native code.
Synchronized‑induced Pinning
When a virtual thread holds a lock and needs to wait, it may remain pinned, preventing other virtual threads from running. Example:
synchronized(object) {
semaphore.acquire(); // should yield but pins
}AJDK21.0.5 modifies the VM to record the lock owner as the virtual thread, allowing the carrier to be released.
Class‑Loading/Initialization Pinning
During class loading, native VM frames appear on the stack, which cannot be switched out. AJDK adds a workaround that triggers a ForkJoinPool compensation thread after a lock‑acquire failure.
Virtual Thread Diagnostic Tools
AJDK21.0.5 enhances diagnostic commands to dump unmounted virtual thread stacks:
jcmd <pid>/<application-name> ThreadAndVThread.dumpThis provides more complete information than the standard OpenJDK Thread.dump_to_file command.
Conclusion
AJDK21.0.5 offers a stable, easy‑to‑use implementation of Java virtual threads with performance gains, pin‑problem mitigations, and improved diagnostics. Developers are encouraged to adopt virtual threads and provide feedback.
Alibaba Cloud Developer
Alibaba's official tech channel, featuring all of its technology innovations.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.
