Multithreading in Java allows multiple threads to run concurrently, enabling efficient CPU utilization and faster performance for I/O-bound or computationally intensive applications. Java provides a rich set of tools for building concurrent programs through the java.lang.Thread
, java.util.concurrent
, and synchronization APIs.
What Is a Thread?
A thread is a lightweight subprocess — the smallest unit of processing. A Java application runs by default with one thread, the main thread, but you can create additional threads to perform tasks in parallel.
Creating Threads in Java
1. Extending the Thread class
java
class MyThread extends Thread {
public void run() {
System.out.println("Thread running...");
}
}
new MyThread().start();
2. Implementing the Runnable interface
java
class MyRunnable implements Runnable {
public void run() {
System.out.println("Runnable running...");
}
}
new Thread(new MyRunnable()).start();
3. Using Callable with ExecutorService
java
ExecutorService executor = Executors.newSingleThreadExecutor();
Future<String> future = executor.submit(() -> "Result from Callable");
System.out.println(future.get()); // blocks until result is available
executor.shutdown();
Thread Lifecycle
A thread goes through several states:
- New
- Runnable
- Blocked
- Waiting/Timed Waiting
- Terminated
You can monitor and control these states using methods like start()
, sleep()
, join()
, wait()
, notify()
, and notifyAll()
.
Thread Safety and Synchronization
Concurrency can introduce race conditions when multiple threads access shared resources. Java provides several tools to manage thread safety:
Synchronized blocks and methods
java
synchronized void increment() {
count++;
}
Locks
java
Lock lock = new ReentrantLock();
lock.lock();
try {
// critical section
} finally {
lock.unlock();
}
Atomic Variables
java
AtomicInteger count = new AtomicInteger();
count.incrementAndGet();
Executor Framework
The java.util.concurrent
package provides powerful abstractions:
- ExecutorService: Manages thread pools.
- ScheduledExecutorService: Supports scheduled tasks.
- Future and CompletableFuture: Handle asynchronous task results.
- CountDownLatch, Semaphore, CyclicBarrier: Provide thread coordination.
Best Practices for Multithreading
- Avoid shared mutable state when possible.
- Use high-level concurrency APIs instead of manually managing threads.
- Always shut down executors to prevent resource leaks.
- Avoid deadlocks by acquiring locks in a consistent order.
- Use thread-safe collections like
ConcurrentHashMap
.
Multithreading in Java unlocks the power of modern processors and improves application responsiveness. By mastering Java’s concurrency tools, you can build scalable and robust multithreaded applications with confidence.