Spring Boot: From Basics to Production · Deployment and Performance

Virtual Threads

Handle more concurrent blocking requests with Java 21 virtual threads.

Virtual threads (Java 21) are lightweight threads managed by the JVM; blocking I/O parks them cheaply instead of tying up OS threads. Enable them with spring.threads.virtual.enabled=true (Boot 3.2+) so Tomcat, @Async and schedulers use virtual threads. They help I/O-bound, blocking code (JDBC, RestClient) scale to many concurrent requests without reactive programming — but downstream limits (database connection pools) still apply.

# application.yml
spring:
  threads:
    virtual:
      enabled: true
  datasource:
    hikari:
      maximum-pool-size: 30      # the real concurrency limit for DB work
// Bound concurrency to a downstream service explicitly
private final Semaphore pricingLimit = new Semaphore(50);

Price price(String sku) throws InterruptedException {
    pricingLimit.acquire();
    try { return pricingClient.get(sku); } finally { pricingLimit.release(); }
}

Common pitfalls

  • Expecting virtual threads to speed up CPU-bound work.
  • Unlimited concurrency overwhelming databases and APIs (use pools/semaphores).
  • Pinning: long blocking inside synchronized blocks on older JDKs (improved in JDK 24).

Key points

  • Cheap blocking for I/O-bound apps
  • One property to enable in Boot
  • Downstream limits still apply

Further reading: Spring Boot: Task execution (virtual threads)

Practice questions

Do virtual threads make a CPU-heavy endpoint faster?

Answer

No. They make blocking I/O cheap so more requests can wait concurrently; CPU-bound work is still limited by cores.

Why is the database pool still important with virtual threads?

Answer

Thousands of virtual threads may want connections at once; the pool caps concurrent queries to what the database can handle.

Open in the app to mark lessons complete, take notes and track your progress.