When you have 200 concurrent users hitting a single-threaded service, you’ll see the connection pool exhaustion error: “java.sql.SQLException: Unable to acquire JDBC Connection”. This is because the traditional threading model in Java is not designed to handle a large number of concurrent connections efficiently.
## PREREQUISITES To follow this tutorial, you need: * Java 26 or later * Spring Boot 3.0 or later * Maven or Gradle * The following Maven dependency:
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency>
For more information on Java dependencies, visit our Java Tutorials Hub. ## UNDERSTANDING VIRTUAL THREADS Virtual threads are a new feature in Java 26 that allows you to create a large number of threads without the overhead of traditional threading. This is achieved by using a thread pool to manage the threads. The thread pool is responsible for creating and managing the threads, and it ensures that the threads are reused and not created unnecessarily.
+---------------+ | Thread Pool | +---------------+ | | v +---------------+ | Virtual Thread | +---------------+ | | v +---------------+ | Application Code | +---------------+
The following table compares the different threading models in Java:
| Threading Model | Description |
|---|---|
| Traditional Threading | Each thread is a separate operating system thread. |
| Thread Pool | A pool of threads that are reused to execute tasks. |
| Virtual Threads | A large number of threads that are managed by a thread pool. |
## STEP-BY-STEP IMPLEMENTATION To implement virtual threads in your Java application, follow these steps: ### Step 1: Create a Virtual Thread Create a new class that extends the Thread class and override the run method.
public class VirtualThread extends Thread { @Override public void run() { // Application code here } }
### Step 2: Create a Thread Pool Create a new instance of the ThreadPoolExecutor class and configure it to use virtual threads.
ThreadPoolExecutor executor = new ThreadPoolExecutor(0, Integer.MAX_VALUE, 60L, TimeUnit.SECONDS, new SynchronousQueue<Runnable>());
### Step 3: Submit Tasks to the Thread Pool Submit tasks to the thread pool using the execute method.
executor.execute(new VirtualThread());
Expected output:
Thread-1 started Thread-2 started ...
For more information on Java Algorithms, visit our tutorials page. ## COMPLETE WORKING EXAMPLE The following is a complete working example of a Java application that uses virtual threads:
package com.example.app; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; public class VirtualThreadExample { public static void main(String[] args) { ExecutorService executor = Executors.newVirtualThreadPerTaskExecutor(); for (int i = 0; i < 10; i++) { executor.submit(new VirtualThread()); } executor.shutdown(); } } class VirtualThread implements Runnable { @Override public void run() { System.out.println(Thread.currentThread().getName() + " started"); // Application code here } }
To test the application, use the following curl command:
curl http://localhost:8080/start
Expected response:
Thread-1 started Thread-2 started ...
For more information on Mastering SQL, visit our tutorials page. ## COMMON MISTAKES AND HOW TO FIX THEM The following are common mistakes that can occur when using virtual threads: ### Mistake 1: Not Closing the Connection Pool If you don’t close the connection pool, you will see the following error:
java.sql.SQLException: Unable to acquire JDBC Connection
To fix this, make sure to close the connection pool when you are done with it.
executor.shutdown();
### Mistake 2: Not Configuring the Thread Pool If you don’t configure the thread pool, you will see the following error:
java.util.concurrent.RejectedExecutionException: Task rejected from java.util.concurrent.ThreadPoolExecutor
To fix this, make sure to configure the thread pool with the correct settings.
ThreadPoolExecutor executor = new ThreadPoolExecutor(0, Integer.MAX_VALUE, 60L, TimeUnit.SECONDS, new SynchronousQueue<Runnable>());
For more information on SOLID Design Principles in Java, visit our tutorials page. ## PERFORMANCE AND PRODUCTION TIPS The following are performance and production tips for using virtual threads:
Production tip: Use the
newVirtualThreadPerTaskExecutormethod to create a thread pool that uses virtual threads.
Production tip: Configure the thread pool to use a
SynchronousQueueas the work queue.
For more information on Java Interview Questions, visit our tutorials page. ## TESTING To test the virtual thread example, you can use the following JUnit test:
import org.junit.Test; import static org.junit.Assert.*; public class VirtualThreadTest { @Test public void testVirtualThread() { ExecutorService executor = Executors.newVirtualThreadPerTaskExecutor(); for (int i = 0; i < 10; i++) { executor.submit(new VirtualThread()); } executor.shutdown(); assertTrue(true); } }
Expected output:
Thread-1 started Thread-2 started ...
## KEY TAKEAWAYS The following are key takeaways from this tutorial: * Virtual threads are a new feature in Java 26 that allows you to create a large number of threads without the overhead of traditional threading. * Virtual threads are managed by a thread pool, which ensures that the threads are reused and not created unnecessarily. * To implement virtual threads, you need to create a thread pool and submit tasks to it using the execute method. * You can configure the thread pool to use a SynchronousQueue as the work queue. * You can test the virtual thread example using a JUnit test. * Virtual threads can improve the performance and scalability of your Java applications.
java-examples — Clone, Star & Contribute

Leave a Reply