ทั้งคู่เป็น Thread Pools จาก Executors factory แต่มีลักษณะการจัดการ Thread และ Queue ต่างกันมาก
ตารางเปรียบเทียบ
| ลำดับ | หัวข้อ | Fixed Thread Pool | Cached Thread Pool |
| 1 | Factory Method | Executors.newFixedThreadPool(n) | Executors.newCachedThreadPool() |
| 2 | Thread Count | **คงที่ (n threads)** ตลอดชีวิต | **Dynamic**: 0 → Integer.MAX_VALUE (สร้างตามความต้องการ) |
| 3 | Queue Type | LinkedBlockingQueue (Unbounded) | SynchronousQueue (Direct handoff, ไม่มี capacity) |
| 4 | Thread Lifetime | อยู่ตลอดจน shutdown() | Idle 60 วินาที → **Terminated & Removed** |
| 5 | Task Submission | Queue ไว้รอ thread ว่าง | หา thread ว่าง → ไม่มี → สร้างใหม่ |
| 6 | Memory/Resource | คงที่, Predictable | ไม่คงที่, อาจสร้างเยอะเกิน (OOM risk) |
| 7 | Throughput | จำกัดโดย n threads | สูงกว่าสำหรับ Short-lived tasks |
| 8 | Rejection | ไม่มี (queue ไม่จำกัด) | ไม่มี (แต่สร้าง thread ใหม่เรื่อยๆ) |
| 9 | Use Case | Long-running tasks, Resource control, Predictable load | Many short-lived tasks, Burst workloads |
Fixed Thread Pool - รายละเอียด
Executors.newFixedThreadPool(4)
┌─────────────────────────────────────┐
│ Thread Pool (4) │
│ Thread-1 Thread-2 Thread-3 Thread-4 ← คงที่ 4 ตัว
└──────────────┬──────────────────────┘
│
┌─────┴─────┐
│ Queue │ ← Unbounded LinkedBlockingQueue
│ (tasks wait here) │
└───────────┘
ตัวอย่าง
ExecutorService fixedPool = Executors.newFixedThreadPool(3);
// Submit 10 tasks - 3 รันพร้อมกัน, 7 รอใน queue
for (int i = 1; i <= 10; i++) {
final int taskId = i;
fixedPool.submit(() -> {
System.out.println("Task " + taskId + " started by " + Thread.currentThread().getName());
sleep(1000);
System.out.println("Task " + taskId + " finished");
});
}
// Tasks รันเป็น batch ของ 3
// Task 1,2,3 start together
// (1s later) Task 4,5,6 start
// (1s later) Task 7,8,9 start
// (1s later) Task 10 start
Cached Thread Pool - รายละเอียด
Executors.newCachedThreadPool()
┌─────────────────────────────────────┐
│ Thread Pool (Dynamic) │
│ Thread-1 Thread-2 ... Thread-N ← สร้าง/ทำลายตามโหลด
└──────────────┬──────────────────────┘
│
┌─────┴─────┐
│Synchronous│ ← No storage! Direct handoff
│ Queue │
└───────────┘
ตัวอย่าง
ExecutorService cachedPool = Executors.newCachedThreadPool();
// Submit 10 tasks - สร้าง 10 threads ทันที (ถ้า idle)
for (int i = 1; i <= 10; i++) {
final int taskId = i;
cachedPool.submit(() -> {
System.out.println("Task " + taskId + " started by " + Thread.currentThread().getName());
sleep(1000);
System.out.println("Task " + taskId + " finished");
});
}
// ทุก task รันพร้อมกัน! (10 threads สร้างขึ้น)
// หลังจบ idle 60s → threads ถูก terminate
SynchronousQueue vs LinkedBlockingQueue
| คุณสมบัติ | LinkedBlockingQueue (Fixed) | SynchronousQueue (Cached) |
| Capacity | Unbounded (default) / Bounded | **0** (ไม่เก็บ element) |
| Mechanism | Producer ใส่ → Consumer ดึง (async) | **Direct Handoff**: Producer block จน Consumer รับ |
| Thread Creation | Queue เต็ม/ว่าง → ไม่สร้าง thread ใหม่ | ไม่มี thread ว่าง → **สร้าง thread ใหม่ทันที** |
| Latency | มี queue delay | ต่ำสุด (handoff ตรง) |
⚠️ ความเสี่ยงของ Cached Thread Pool
// อันตราย! ถ้ามี burst ของ long-running tasks
ExecutorService cached = Executors.newCachedThreadPool();
for (int i = 0; i < 10000; i++) {
cached.submit(() -> {
// Long running task (เช่น DB query, HTTP call)
try { Thread.sleep(30000); } catch (InterruptedException ignored) {}
});
}
// → สร้าง 10,000 threads! → OOM / System crash
Best Practices & Alternatives
1. ใช้ ThreadPoolExecutor โดยตรง (แนะนำ Production)
// Custom Fixed Pool with Bounded Queue + Rejection Policy
ThreadPoolExecutor executor = new ThreadPoolExecutor(
4, // corePoolSize
8, // maximumPoolSize
60L, TimeUnit.SECONDS, // keepAliveTime
new LinkedBlockingQueue<>(100), // Bounded queue!
new ThreadPoolExecutor.CallerRunsPolicy() // Rejection: caller runs task
);
// Custom Cached-like Pool with Limits
ThreadPoolExecutor cached = new ThreadPoolExecutor(
0, Integer.MAX_VALUE,
60L, TimeUnit.SECONDS,
new SynchronousQueue<>(),
new ThreadFactoryBuilder().setNameFormat("cached-%d").build(),
new ThreadPoolExecutor.AbortPolicy() // Or CallerRunsPolicy
);
2. ใช้ Virtual Threads (Java 21+)
// Java 21: Virtual threads - เหมาะสำหรับ high concurrency I/O
ExecutorService virtualPool = Executors.newVirtualThreadPerTaskExecutor();
// ไม่ต้องกังวล thread count - virtual threads รองรับล้านๆ
สรุปการเลือก
| สถานการณ์ | แนะนำ | เหตุผล |
| Fixed จำนวน concurrent tasks (CPU-bound) | FixedThreadPool / Custom ThreadPoolExecutor | ควบคุม resource, ป้องกัน overload |
| Short-lived I/O tasks, Burst traffic | CachedThreadPool (with limits) | Low latency, auto-scale |
| Long-running tasks | FixedThreadPool (bounded queue) | ป้องกัน thread explosion |
| High concurrency I/O (Java 21+) | VirtualThreadPerTaskExecutor | Scalable, lightweight |
| Production systems | Custom ThreadPoolExecutor | Full control: queue size, rejection, monitoring |