Computer >> บทช่วยสอนคอมพิวเตอร์ >  >> การเขียนโปรแกรม >> Java

ความแตกต่างระหว่าง Fixed Thread Pool และ Cached Thread Pool ใน Java

ทั้งคู่เป็น Thread Pools จาก Executors factory แต่มีลักษณะการจัดการ Thread และ Queue ต่างกันมาก

ตารางเปรียบเทียบ

ลำดับหัวข้อFixed Thread PoolCached Thread Pool
1Factory MethodExecutors.newFixedThreadPool(n)Executors.newCachedThreadPool()
2Thread Count**คงที่ (n threads)** ตลอดชีวิต**Dynamic**: 0 → Integer.MAX_VALUE (สร้างตามความต้องการ)
3Queue TypeLinkedBlockingQueue (Unbounded)SynchronousQueue (Direct handoff, ไม่มี capacity)
4Thread Lifetimeอยู่ตลอดจน shutdown()Idle 60 วินาที → **Terminated & Removed**
5Task SubmissionQueue ไว้รอ thread ว่างหา thread ว่าง → ไม่มี → สร้างใหม่
6Memory/Resourceคงที่, Predictableไม่คงที่, อาจสร้างเยอะเกิน (OOM risk)
7Throughputจำกัดโดย n threadsสูงกว่าสำหรับ Short-lived tasks
8Rejectionไม่มี (queue ไม่จำกัด)ไม่มี (แต่สร้าง thread ใหม่เรื่อยๆ)
9Use CaseLong-running tasks, Resource control, Predictable loadMany 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)
CapacityUnbounded (default) / Bounded**0** (ไม่เก็บ element)
MechanismProducer ใส่ → Consumer ดึง (async)**Direct Handoff**: Producer block จน Consumer รับ
Thread CreationQueue เต็ม/ว่าง → ไม่สร้าง 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 trafficCachedThreadPool (with limits)Low latency, auto-scale
Long-running tasksFixedThreadPool (bounded queue)ป้องกัน thread explosion
High concurrency I/O (Java 21+)VirtualThreadPerTaskExecutorScalable, lightweight
Production systemsCustom ThreadPoolExecutorFull control: queue size, rejection, monitoring