⚡ Modern Java Concurrency: Threads, Executors & Virtual Threads
⚡ Modern Java Concurrency: Threads, Executors & Virtual Threads
Understanding Java's multi-threading and concurrency mechanisms is essential for writing performant, safe, and maintainable applications. This post explores thread creation, synchronization, executors, modern virtual threads, common concurrency problems, and tools for diagnosing issues.
1. ๐งต Thread Creation
- Extending Thread: Override
run().
class MyThread extends Thread {
public void run() {
System.out.println("Thread running");
}
}
new MyThread().start();
Runnable task = () -> System.out.println("Runnable running");
new Thread(task).start();
Callable<Integer> task = () -> 42; Future<Integer> future = Executors.newSingleThreadExecutor().submit(task); System.out.println(future.get());
try (var executor = Executors.newVirtualThreadPerTaskExecutor()) {
executor.submit(() -> System.out.println("Virtual thread running"));
}
2. ๐ Synchronization & Locks
Ensure only one thread accesses critical sections:
- synchronized: Built-in object/method lock.
- ReentrantLock / ReadWriteLock / StampedLock: Advanced locking.
- Semaphores: Limit concurrent access.
- CountDownLatch / Phaser / CyclicBarrier: Coordinate multiple threads.
3. ๐ Executor Framework
- Interfaces: Executor, ExecutorService, ThreadPoolExecutor
- Factories:
- newSingleThreadExecutor()
- newFixedThreadPool(n)
- newCachedThreadPool()
- newScheduledThreadPool(n)
- newVirtualThreadPerTaskExecutor() (Java 19+)
- Methods:
- execute(Runnable) - no result
- submit(Runnable / Callable) - returns Future
- invokeAll(Collection<Callable>) / invokeAny(...) - execute multiple tasks
4. ⚠️ Common Concurrency Problems
- Deadlock: Two threads wait forever for each other's locks.
Thread 1: lock(A) then lock(B) Thread 2: lock(B) then lock(A) → deadlock
int counter = 0; Runnable r = () -> counter++; // multiple threads increment → unexpected results
5. ๐พ Thread Diagnostics & Memory Issues
- Thread dump: Snapshot of all threads.
- Memory leaks: Objects remain in heap but unused. Causes:
- Static references
- Unclosed resources (streams, connections)
- Tools: JProfiler, VisualVM, JConsole, Flight Recorder (JFR)
6. ๐ Summary Table of Thread Pools
| Thread Pool | Behavior | Use Case |
|---|---|---|
| newFixedThreadPool(int n) | Fixed threads. Tasks queued if busy. | Predictable concurrency |
| newCachedThreadPool() | Creates threads on demand, reuses idle ones. | Short-lived tasks, bursts |
| newSingleThreadExecutor() | Single worker thread sequential execution. | Ordered tasks |
| newScheduledThreadPool(int n) | Execute tasks periodically or with delay. | Recurring/scheduled tasks |
| newVirtualThreadPerTaskExecutor() | Lightweight virtual threads, thousands possible. | High concurrency, scalable microservices |
7. ๐ Modern Java Utilities
- CompletableFuture: Async computation, combine multiple futures.
- ForkJoinPool: Efficient for parallel streams / divide-and-conquer.
- Structured Concurrency (Java 21+): Manage multiple tasks as a single unit with
StructuredTaskScope. - Volatile & transient: Volatile for visibility, transient for skipping serialization.
8. ๐ Visual Summary
Thread
Platform vs Virtual Thread
Deadlock
Thread waiting forever
Race
Shared data conflict
Labels: Java, Threads, Concurrency, Executor, Synchronization, Deadlock, Race Condition, Virtual Threads, Structured Concurrency
Comments
Post a Comment