Computer >> Hướng Dẫn Máy Tính >  >> Lập Trình >> Java

Khác biệt giữa Fixed Thread Pool và Cached Thread Pool trong Java

Cả hai là ExecutorService do Executors tạo ra, dựa trên ThreadPoolExecutor nhưng cấu hình queue và thread lifecycle khác biệt.

Bảng so sánh

Tiêu chíFixed Thread PoolCached Thread Pool
Factory methodExecutors.newFixedThreadPool(nThreads)Executors.newCachedThreadPool()
ThreadPoolExecutor configcore=max=nThreads, keepAlive=0, queue=LinkedBlockingQueue (unbounded)core=0, max=Integer.MAX_VALUE, keepAlive=60s, queue=SynchronousQueue
Queue typeUnbounded BlockingQueue (LinkedBlockingQueue)Direct handoff queue (SynchronousQueue – capacity 0)
Thread creationTạo sẵn nThreads khi submit task đầu tiên. Giữ cố định.Tạo thread mới khi cần (queue full – luôn full vì SynchronousQueue). Reuse idle thread.
Thread terminationKhông tự terminate (keepAlive=0). Chỉ chết khi shutdown().Thread idle > 60s → terminate. Pool co lại về 0.
Pool size behaviorCố định (fixed)Động: 0 → Integer.MAX_VALUE
BackpressureQueue unbounded → task chờ vô hạn → OOM risk nếu producer > consumer.Không queue (handoff) → task bị reject nếu không tạo thread kịp (hoặc tạo thread mới).
Use caseGiới hạn concurrency, workload ổn định, long-running tasks, server handling requests.Nhiều short-lived tasks, bursty workload, async event handling, parallel independent tasks.
Rủi roQueue unbounded → OOM. Thread leak nếu task block forever.Tạo thread không giới hạn → OOM, thread thrashing, CPU context switch overhead.

Ví dụ Fixed Thread Pool

import java.util.concurrent.*;

public class FixedThreadPoolDemo {
    public static void main(String[] args) throws InterruptedException {
        ExecutorService executor = Executors.newFixedThreadPool(3);
        CountDownLatch latch = new CountDownLatch(5);
        
        for (int i = 1; i <= 5; i++) {
            final int id = i;
            executor.submit(() -> {
                try {
                    System.out.println("Task " + id + " running on " + Thread.currentThread().getName());
                    Thread.sleep(1000);
                } catch (InterruptedException e) { Thread.currentThread().interrupt(); }
                finally { latch.countDown(); }
            });
        }
        
        latch.await();
        System.out.println("All tasks done. Active threads: " + ((ThreadPoolExecutor)executor).getActiveCount());
        executor.shutdown();
    }
}

Ví dụ Cached Thread Pool

import java.util.concurrent.*;

public class CachedThreadPoolDemo {
    public static void main(String[] args) throws InterruptedException {
        ExecutorService executor = Executors.newCachedThreadPool();
        CountDownLatch latch = new CountDownLatch(10);
        
        // Submit 10 short tasks nhanh chóng
        for (int i = 1; i <= 10; i++) {
            final int id = i;
            executor.submit(() -> {
                System.out.println("Task " + id + " on " + Thread.currentThread().getName());
                try { Thread.sleep(100); } catch (InterruptedException e) { Thread.currentThread().interrupt(); }
                latch.countDown();
            });
        }
        
        latch.await();
        System.out.println("Pool size after: " + ((ThreadPoolExecutor)executor).getPoolSize()); // Sẽ giảm dần về 0
        Thread.sleep(70000); // Chờ 70s > keepAlive 60s
        System.out.println("Pool size after 70s idle: " + ((ThreadPoolExecutor)executor).getPoolSize()); // 0
        executor.shutdown();
    }
}

Best Practice: Tự custom ThreadPoolExecutor (Production)

// Fixed pool với bounded queue – an toàn hơn
ExecutorService fixed = new ThreadPoolExecutor(
    10, 10, 0L, TimeUnit.MILLISECONDS,
    new LinkedBlockingQueue<>(100), // Bounded queue!
    new ThreadFactoryBuilder().setNameFormat("fixed-worker-%d").build(),
    new ThreadPoolExecutor.AbortPolicy() // Hoặc CallerRunsPolicy
);

// Cached pool với giới hạn max threads
ExecutorService cached = new ThreadPoolExecutor(
    0, 50, 60L, TimeUnit.SECONDS,
    new SynchronousQueue<>(),
    new ThreadFactoryBuilder().setNameFormat("cached-worker-%d").build(),
    new ThreadPoolExecutor.CallerRunsPolicy() // Backpressure: caller chạy task nếu pool full
);

Tóm tắt chọn lựa

  • Fixed Thread Pool: Server xử lý request, worker pool ổn định, cần kiểm soát resource.
  • Cached Thread Pool: Batch processing, event-driven, short tasks, burst traffic – nhưng cẩn thận unbounded thread creation.
  • Production: Luôn custom ThreadPoolExecutor với bounded queue, named threads, rejection policy, monitoring.