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

Khác biệt giữa CountDownLatch và CyclicBarrier trong Java Concurrency

Cả hai đều là synchronization aids (công cụ đồng bộ) trong package java.util.concurrent, nhưng phục vụ mục đích khác nhau.

Bản chất cốt lõi

  • CountDownLatch: "Đếm ngược" – một hoặc nhiều thread chờ cho đến khi một tập hợp tác vụ (tasks) hoàn thành. One-shot (dùng một lần).
  • CyclicBarrier: "Rào chắn vòng" – một tập hợp thread chờ nhau tại một điểm gặp (barrier point) chung. Reusable (tái sử dụng được).

Bảng so sánh chi tiết

Tiêu chíCountDownLatchCyclicBarrier
Mục đíchChờ N task hoàn thànhChờ N thread gặp nhau tại barrier
Tái sử dụngKhông (count xuống 0 thì xong)Có (reset() hoặc tự động reset khi tất cả party đến)
ConstructorCountDownLatch(int count)CyclicBarrier(int parties) hoặc CyclicBarrier(int parties, Runnable barrierAction)
Thread/TaskĐếm task (countDown)Đếm thread/party (await)
Phương thức chờawait() (cho thread main/manager)await() (cho các worker thread)
Phương thức giảm countcountDown() (gọi khi task xong)Tự động khi thread gọi await()
Barrier ActionKhông cóCó (Runnable chạy khi tất cả party đã đến, trước khi release)
Exception khi interruptChỉ thread bị interrupt ném InterruptedExceptionTất cả thread chờ khác ném BrokenBarrierException
AdvanceableCó thể tăng count thủ công? Không (chỉ countDown)Không (không tăng parties được)

Ví dụ CountDownLatch: Main thread chờ workers khởi tạo xong

import java.util.concurrent.*;

public class CountDownLatchDemo {
    public static void main(String[] args) throws InterruptedException {
        int workerCount = 3;
        CountDownLatch latch = new CountDownLatch(workerCount);
        ExecutorService executor = Executors.newFixedThreadPool(workerCount);
        
        for (int i = 1; i <= workerCount; i++) {
            final int id = i;
            executor.submit(() -> {
                try {
                    Thread.sleep(1000 + id * 500); // Giả lập khởi tạo
                    System.out.println("Worker " + id + " ready");
                } catch (InterruptedException e) {
                    Thread.currentThread().interrupt();
                } finally {
                    latch.countDown(); // Báo xong việc
                }
            });
        }
        
        System.out.println("Main: Waiting for workers...");
        latch.await(); // Block cho đến khi count = 0
        System.out.println("Main: All workers ready! Starting app...");
        executor.shutdown();
    }
}

Ví dụ CyclicBarrier: Threads đồng bộ tại checkpoint (ví dụ: game multiplayer, map-reduce)

import java.util.concurrent.*;

public class CyclicBarrierDemo {
    public static void main(String[] args) {
        int parties = 3;
        // Barrier action: chạy khi đủ 3 thread await()
        CyclicBarrier barrier = new CyclicBarrier(parties, () -> 
            System.out.println(">>> All parties arrived! Barrier action executed."));
        
        ExecutorService executor = Executors.newFixedThreadPool(parties);
        
        for (int i = 1; i <= parties; i++) {
            final int id = i;
            executor.submit(() -> {
                try {
                    System.out.println("Thread " + id + " doing phase 1...");
                    Thread.sleep(500 + id * 300);
                    barrier.await(); // Chờ ở barrier 1
                    
                    System.out.println("Thread " + id + " doing phase 2...");
                    Thread.sleep(300);
                    barrier.await(); // Chờ ở barrier 2 (tái sử dụng!)
                    
                    System.out.println("Thread " + id + " finished.");
                } catch (InterruptedException | BrokenBarrierException e) {
                    e.printStackTrace();
                }
            });
        }
        executor.shutdown();
    }
}

Khi nào dùng cái nào?

  • CountDownLatch: Khởi tạo tài nguyên (DB pool, cache, config), chờ nhiều service start xong, parallel computation chờ kết quả.
  • CyclicBarrier: Phân chia công việc phase-based (map-reduce, game loop, pipeline stages), cần tái sử dụng barrier nhiều lần.

Lưu ý: Phaser (Java 7+)

Phaser linh hoạt hơn cả hai: hỗ trợ dynamic registration/deregistration parties, phase number, tiered synchronization. Dùng cho phức tạp hơn.