Crashes, No Sound, or Screen Glitches?
Random freezes, missing sound and display glitches usually trace back to one bad driver. Find and replace yours safely.Free scan · under a minuteWindows Errors? Fix Them Before They Spread
Repair common Windows errors and clear accumulated junk for a smoother, more stable PC - no reinstall needed.Free scan · no reinstallSet spring.threads.virtual.enabled=true on Java 21 or later and Spring Boot runs your work on virtual threads. That helps most when requests spend much of their time waiting on blocking I/O. It does not speed up CPU-bound code, and it does not raise the capacity of your database or any remote service. This article covers what changes when you flip the switch, what stops mattering, and what can still go wrong on Java 21.
What changes when you move from thread pools to virtual threads
Platform threads map to operating-system threads and are comparatively costly, so servers cap them in pools. Virtual threads are, in the words of the JEP authors Ron Pressler and Alan Bateman, “a lightweight implementation of threads that is provided by the JDK rather than the OS” (JEP 444). When a virtual thread blocks in a supported I/O operation, it can be suspended and its carrier platform thread freed to run other work. You can then keep a simple thread-per-request style and still serve many concurrent requests, without rewriting blocking code into an asynchronous style.
As an Amazon Associate I earn from qualifying purchases.
Virtual threads were finalized in Java 21. The current Spring Boot reference states, “Virtual threads require Java 21 or later,” and strongly recommends Java 24 or later for the best experience (Spring Boot reference). Java 21 is a valid baseline, but the guidance below depends on your exact JDK and Spring Boot versions. Later JDKs can behave differently, especially around pinning.
How to enable virtual threads in Spring Boot
- Run on Java 21 or later, with a Spring Boot version that supports the property.
- Add to
application.properties:spring.threads.virtual.enabled=true(YAML equivalent:spring: threads: virtual: enabled: true). - Restart and confirm in a thread dump or logs that request-handling threads are virtual.
- Load-test with your real blocking mix and downstream limits before rolling out.
The Spring Boot reference advises reading the Java virtual-thread documentation first. The Oracle Java 21 guide is the official operational reference.
What happens to your thread-pool settings
Once virtual threads are enabled, properties that configure thread pools stop having an effect. Virtual threads are scheduled on a JVM-wide platform-thread pool rather than dedicated pools (Spring Boot reference). Raising a request-thread pool size is therefore no longer your main control for concurrency.
Do not pool virtual threads either. JEP 444 says to create a virtual thread per task. Because they are cheap and plentiful, a pool would only act as a limiter, and that is the wrong tool for the job.
Rank #2
Where limits move: scarce resources
A pool size used to double as an accidental limit on database connections and remote calls. With virtual threads that limit disappears, so make it explicit at the resource boundary:
Quick wins for a faster PC:
Fix the driver behind crashes, sound loss and screen glitchesFind Drivers →Clear out junk files and repair common Windows errorsFree Scan →- Database: the connection pool size still caps real concurrency. Many virtual threads will simply queue for connections.
- Remote APIs: apply rate limits, bulkheads or semaphores where the call is made, sized to what the downstream service tolerates.
- Memory and CPU: more in-flight requests means more live objects, and CPU-bound work gains nothing.
- Thread locals: JEP 444 cautions that very large numbers of virtual threads change assumptions about thread-local use. Do not rely on thread locals to pool costly resources across tasks.
Do virtual threads make Spring Boot faster?
They improve concurrency, not per-request speed. Gains are conditional on waiting-heavy workloads. The official sources give no universal throughput multiplier, and none is quoted here. If you cite a benchmark, check which JDK, framework, workload and downstream constraints it used. Measure your own service.
| Axis | Platform-thread pool | Virtual threads |
|---|---|---|
| Blocking-I/O concurrency | Bounded by pool size | Carriers are released while supported blocking calls wait |
| CPU-bound throughput | Bounded by cores | Do not assume improvement |
| Downstream bottlenecks | Pool size often limits them implicitly | Need explicit limits |
| Pinning | Not applicable | Java 21 caveats, below |
| Lifecycle | Non-daemon threads available | Daemon threads only |
Pinning on Java 21
JEP 444 documents two Java 21 situations in which a virtual thread cannot unmount from its carrier while blocking:
- Code running inside a
synchronizedblock or method. - Code running in a native method or foreign function.
Pinning is not necessarily a bug. Frequent or long blocking while pinned can capture carriers and hurt scalability. The JEP advises fixing frequent, long-lived pinning and not replacing simple, infrequent synchronization indiscriminately.
Rank #4
How to investigate
- Record the JFR event
jdk.VirtualThreadPinned. - Start the JVM with
-Djdk.tracePinnedThreads=fullto print a full stack trace when a thread blocks while pinned.
Look at where blocking I/O or lock waits occur inside synchronized sections, including in libraries such as JDBC drivers and clients. Treat this as Java 21 guidance and re-check on newer JDKs.
Do these 3 things before closing this tab:
1Repair Windows errors before they cause bigger problems2Fix the driver behind crashes, sound loss and screen glitches3Clear out junk files and repair common Windows errorsDaemon threads and keeping the JVM alive
Virtual threads are daemon threads, and a JVM exits when only daemon threads remain. Spring Boot warns this can matter for @Scheduled beans and other technologies, and recommends spring.main.keep-alive=true to keep the JVM alive when all threads are virtual. Verify shutdown and keep-alive behavior in your own application lifecycle rather than assuming scheduled work keeps the process running. Web applications with a running server typically stay up through the server’s own threads, so this mostly bites worker or batch-style apps.
Quick Recap
Best Value
Rollout checklist
- Confirm JDK and Spring Boot versions; prefer Java 24 or later if you can, per Spring’s recommendation.
- Enable the property in one environment and compare latency and throughput under realistic load.
- Set explicit limits for connection pools and remote calls.
- Run with pinning diagnostics during the load test.
- Add
spring.main.keep-alive=trueif the app relies on non-web or scheduled work to stay alive. - Remove tuning that assumed a request-thread pool.
Product prices and availability are accurate as of the date/time indicated and are subject to change. Any price and availability information displayed on Amazon at the time of purchase will apply.




