Project Loom (JDK 21) brings virtual threads and structured concurrency to Java. Learn vocabulary for carrier threads, ForkJoinPool scheduling, pinning on synchronized blocks, newVirtualThreadPerTaskExecutor, StructuredTaskScope, ScopedValue vs ThreadLocal, and migration considerations.
0 / 5 completed
1 / 5
A Java developer creates a virtual thread with Thread.ofVirtual().start(runnable). On which OS thread does this virtual thread run?
Virtual threads are multiplexed onto carrier threads, which are platform (OS) threads from the JVM's internal ForkJoinPool. When a virtual thread blocks (e.g., on I/O), it is unmounted from its carrier, freeing the carrier to run another virtual thread. The mapping is M:N (many virtual to few platform threads).
2 / 5
A virtual thread calls a synchronized method that blocks on I/O inside. What is the Project Loom behavior in JDK 21?
In JDK 21, virtual threads are pinned when they block inside a synchronized block or method. The carrier thread cannot be reused for other virtual threads during this time. The fix is to replace synchronized with java.util.concurrent.locks.ReentrantLock, which supports proper virtual thread unmounting.
3 / 5
What is the purpose of Executors.newVirtualThreadPerTaskExecutor() in Project Loom?
newVirtualThreadPerTaskExecutor() creates an ExecutorService that spawns a new virtual thread per submitted task. Since virtual threads are lightweight (~few KB), this is efficient even for millions of concurrent tasks. Unlike traditional thread pools, there is no pool size limit — the JVM manages carrier threads internally.
4 / 5
A team uses ThreadLocal extensively for per-request context in a servlet application migrating to virtual threads. What concern should they address?
ThreadLocal works with virtual threads but the memory concern is significant: traditional thread pools reuse threads and clear/reset locals, but virtual-thread-per-task executors create new threads per task. If locals hold large objects and remove() is never called, GC pressure increases. Project Loom also introduces ScopedValue as a preferred alternative.
5 / 5
Project Loom's structured concurrency API (JEP 453) uses StructuredTaskScope. What invariant does it enforce?
StructuredTaskScope enforces the structured concurrency invariant: child tasks cannot outlive their parent scope. When the scope.join() call returns (or throws), all forked subtasks have either completed or been cancelled. This eliminates thread leaks and makes concurrent code's lifetime as clear as sequential code's.