ExecutorService (Java 5+) quản lý thread pool — bạn submit Runnable/Callable, executor lo phần còn lại.
new Thread() thủ công burst 10K request → 10K OS thread → OOM. Không reuse, không backpressure.
ExecutorService exec = Executors.newFixedThreadPool(10);
exec.execute(() -> handle(request)); // Runnable
Future<String> f = exec.submit(() -> fetch()); // Callable → Future<T>
exec.shutdown();
if (!exec.awaitTermination(30, TimeUnit.SECONDS)) exec.shutdownNow();Factory trong Executors:
| Factory | Khi dùng |
|---|---|
newFixedThreadPool(n) | CPU-bound |
newCachedThreadPool() | Task ngắn, ít — nguy hiểm nếu burst (unbounded) |
newScheduledThreadPool(n) | Task định kỳ/delay |
newVirtualThreadPerTaskExecutor() (Java 21+) | I/O-bound — RECOMMENDED 2026 |
Sizing: CPU-bound = số core; I/O-bound truyền thống = cores × (1 + wait/compute); Java 21+ → Virtual Threads.
Sai lầm hay gặp: không shutdown (leak), newCachedThreadPool() không giới hạn (OOM), default queue unbounded, nuốt exception trong task không log.
Java 21+ pattern:
try (var exec = Executors.newVirtualThreadPerTaskExecutor()) {
// auto-shutdown khi try kết thúc
}Đừng new Thread() thủ công trong production.
Virtual Threads là chuẩn mới cho I/O workload.
ExecutorService (Java 5+) manages a thread pool — you submit Runnable/Callable, the executor handles the rest.
A manual new Thread() burst of 10K requests → 10K OS threads → OOM. No reuse, no backpressure.
ExecutorService exec = Executors.newFixedThreadPool(10);
exec.execute(() -> handle(request)); // Runnable
Future<String> f = exec.submit(() -> fetch()); // Callable → Future<T>
exec.shutdown();
if (!exec.awaitTermination(30, TimeUnit.SECONDS)) exec.shutdownNow();Factories in Executors:
| Factory | When to use |
|---|---|
newFixedThreadPool(n) | CPU-bound |
newCachedThreadPool() | Sparse short tasks — dangerous on bursts (unbounded) |
newScheduledThreadPool(n) | Periodic/delayed |
newVirtualThreadPerTaskExecutor() (Java 21+) | I/O-bound — RECOMMENDED in 2026 |
Sizing: CPU-bound = cores; traditional I/O-bound = cores × (1 + wait/compute); Java 21+ → Virtual Threads.
Common mistakes: forgetting to shut down (leak), unbounded newCachedThreadPool() (OOM), default unbounded queue, swallowing task exceptions without logging.
Java 21+ pattern:
try (var exec = Executors.newVirtualThreadPerTaskExecutor()) {
// auto-shutdown when try block ends
}Never call new Thread() directly in production.
Virtual Threads are the new standard for I/O workloads.