Thread
class, which was the traditional way to handle concurrent execution, Java has now introduced virtual threads in Java 19 (incubating) and made them standard in Java 21. This blog will explore the journey of Java multi - threading from traditional threads to the new and exciting virtual threads.In Java, a thread is an independent path of execution within a program. Each thread has its own call stack, program counter, and local variables. The Thread
class in Java represents a thread of execution. When you create an instance of the Thread
class and call its start()
method, a new thread of execution is spawned.
There are two common ways to create and start a thread in Java:
Thread
classclass MyThread extends Thread {
@Override
public void run() {
System.out.println("Running thread: " + Thread.currentThread().getName());
}
}
public class TraditionalThreadExample1 {
public static void main(String[] args) {
MyThread myThread = new MyThread();
myThread.start();
}
}
Runnable
interfaceclass MyRunnable implements Runnable {
@Override
public void run() {
System.out.println("Running thread: " + Thread.currentThread().getName());
}
}
public class TraditionalThreadExample2 {
public static void main(String[] args) {
MyRunnable myRunnable = new MyRunnable();
Thread thread = new Thread(myRunnable);
thread.start();
}
}
OutOfMemoryError
. So, it’s important to limit the number of threads.synchronized
blocks or methods, or more advanced concurrency utilities like ReentrantLock
.class Counter {
private int count = 0;
public synchronized void increment() {
count++;
}
public int getCount() {
return count;
}
}
public class SynchronizationExample {
public static void main(String[] args) throws InterruptedException {
Counter counter = new Counter();
Thread t1 = new Thread(() -> {
for (int i = 0; i < 1000; i++) {
counter.increment();
}
});
Thread t2 = new Thread(() -> {
for (int i = 0; i < 1000; i++) {
counter.increment();
}
});
t1.start();
t2.start();
t1.join();
t2.join();
System.out.println("Final count: " + counter.getCount());
}
}
Virtual threads are lightweight threads managed by the Java Virtual Machine (JVM). Unlike traditional threads, which are mapped to operating - system threads, virtual threads are multiplexed over a small number of operating - system threads. This allows the JVM to run a large number of virtual threads efficiently, as the overhead of creating and managing virtual threads is much lower.
To create and start a virtual thread, you can use the Thread.startVirtualThread()
method or the Executors.newVirtualThreadPerTaskExecutor()
method.
Thread.startVirtualThread()
public class VirtualThreadExample1 {
public static void main(String[] args) {
Thread.startVirtualThread(() -> {
System.out.println("Running virtual thread: " + Thread.currentThread().getName());
});
}
}
Executors.newVirtualThreadPerTaskExecutor()
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class VirtualThreadExample2 {
public static void main(String[] args) {
ExecutorService executor = Executors.newVirtualThreadPerTaskExecutor();
executor.submit(() -> {
System.out.println("Running virtual thread: " + Thread.currentThread().getName());
});
executor.shutdown();
}
}
Feature | Traditional Threads | Virtual Threads |
---|---|---|
Resource Overhead | High. Each thread has its own stack space and is mapped to an operating - system thread. | Low. Managed by the JVM and multiplexed over a small number of operating - system threads. |
Scalability | Limited. Creating too many threads can lead to resource exhaustion. | High. Can handle a large number of concurrent tasks efficiently. |
Use Cases | CPU - bound tasks where the thread is actively using the CPU for a long time. | I/O - bound tasks where the thread spends most of its time waiting for I/O operations. |
The evolution of Java multi - threading from traditional threads to virtual threads is a significant step forward. Traditional threads have served Java developers well for many years, but they have limitations in terms of resource consumption and scalability. Virtual threads, on the other hand, offer a more efficient way to handle concurrent tasks, especially I/O - bound ones. By understanding the concepts, usage methods, and best practices of both traditional and virtual threads, developers can make informed decisions on which approach to use in different scenarios.