Multithreading
Java supports multithreading natively — running several threads in parallel within a single program. Every Java program has at least one thread (the main thread). Multithreading improves application performance and responsiveness, especially for I/O-bound and CPU-bound tasks.
A Thread can be created in two ways: extending Thread or implementing Runnable (the latter is recommended, because Java supports multiple interfaces). ExecutorService (Java 5+) is the modern way to manage thread pools — more efficient than creating threads manually.
Virtual Threads (Java 21+) are a revolution — lightweight threads managed by the JVM, allowing you to create millions of threads with minimal overhead. A good fit for I/O-bound workloads such as web servers and database clients. Use Thread.ofVirtual().start(runnable).
Ways to Create Threads:
| Approach | Example | Advantages |
|---|---|---|
implements Runnable |
new Thread(runnable) |
Flexible, can implement multiple interfaces |
extends Thread |
new MyThread() |
Simple for basic threads |
Callable<V> |
ExecutorService.submit() |
Returns a result (Future) |
| Virtual Thread | Thread.ofVirtual() |
Lightweight, Java 21+ |
Code Example
import java.util.concurrent.*;
public class MultithreadingJava {
public static void main(String[] args) throws Exception {
// Way 1: Runnable
Runnable task1 = () -> {
for (int i = 1; i <= 5; i++) {
System.out.println("[Thread-1] Iterasi " + i);
try { Thread.sleep(500); } catch (InterruptedException e) {}
}
};
Thread thread1 = new Thread(task1, "Worker-1");
thread1.start();
// Way 2: Lambda
Thread thread2 = new Thread(() -> {
for (int i = 1; i <= 5; i++) {
System.out.println("[Thread-2] Iterasi " + i);
try { Thread.sleep(300); } catch (InterruptedException e) {}
}
}, "Worker-2");
thread2.start();
// Wait for completion
thread1.join();
thread2.join();
System.out.println("Both threads done.");
// ExecutorService (modern)
ExecutorService executor = Executors.newFixedThreadPool(3);
for (int i = 1; i <= 5; i++) {
final int task = i;
executor.submit(() ->
System.out.println("Task " + task + " di " + Thread.currentThread().getName())
);
}
executor.shutdown();
executor.awaitTermination(5, java.util.concurrent.TimeUnit.SECONDS);
// Virtual Thread (Java 21+)
Thread.startVirtualThread(() ->
System.out.println("Virtual thread: " + Thread.currentThread())
);
Thread.sleep(100); // give it time to print
}
}
Code Explanation
- Runnable:
() -> { ... }is a lambda that implements the Runnable interface — it contains the code that will run on a new thread. - Thread.start(): starts a new thread. Thread.sleep(ms) pauses a thread. Thread.join() waits for a thread to finish.
- ExecutorService:
newFixedThreadPool(3)creates a pool of 3 threads.submit()adds a task to the queue.shutdown()+awaitTermination()waits for all tasks to complete. - Virtual Threads:
Thread.ofVirtual().start()creates a lightweight thread — you can have thousands of them without big overhead.
Everyday Example
A parallel download program for several files:
import java.util.concurrent.*;
import java.util.List;
public class DownloadParalel {
static String download(String url) throws InterruptedException {
System.out.println("Mendownload: " + url);
Thread.sleep(2000); // simulate the download
return "Done: " + url;
}
public static void main(String[] args) throws Exception {
List<String> urls = List.of(
"https://example.com/file1.zip",
"https://example.com/file2.zip",
"https://example.com/file3.zip",
"https://example.com/file4.zip"
);
ExecutorService executor = Executors.newFixedThreadPool(4);
List<Future<String>> futures = urls.stream()
.map(url -> executor.submit(() -> download(url)))
.toList();
for (Future<String> f : futures) {
System.out.println(f.get());
}
executor.shutdown();
System.out.println("All downloads done!");
}
}
Summary
Multithreading is an important Java feature for performance and responsiveness. Use ExecutorService rather than creating Threads manually, for better control. Virtual Threads (Java 21+) are a game changer for I/O-bound workloads — as lightweight as goroutines in Go or coroutines in Kotlin.