ทั้งคู่อยู่ใน java.util.concurrent ใช้สำหรับ **synchronization** ระหว่าง threads แต่มีจุดประสงค์และการทำงานต่างกัน
ตารางเปรียบเทียบ
| ลำดับ | หัวข้อ | CountDownLatch | CyclicBarrier |
|---|---|---|---|
| 1 | วัตถุประสงค์ | รอให้ **ชุดของ tasks** เสร็จสิ้น (one-shot) | รอให้ **ชุดของ threads** พบกันที่ barrier point (reusable) |
| 2 | นับอะไร | นับ **tasks** (countDown) | นับ **threads** (await) |
| 3 | Reusable | **ไม่ได้** (ใช้ครั้งเดียว count ลงถึง 0 จบ) | **ได้** (reset อัตโนมัติหลังทุก barrier) |
| 4 | Runnable Action | ไม่มี | มี (constructor รับ Runnable รันเมื่อทุก thread มาถึง) |
| 5 | Exception Handling | Thread ที่ interrupt ได้ InterruptedException เดียว | Thread หนึ่ง interrupt → ทุก thread ได้ BrokenBarrierException |
| 6 | Advanceable | ได้ (countDown จาก thread ไหนก็ได้) | ไม่ได้ (ต้อง await ทุก thread) |
| 7 | Use Case | เริ่มงานพร้อมกัน, รอ initialization, parallel tasks | Parallel algorithms, phased computation, games |
CountDownLatch - One-shot Countdown
หลักการ: Main thread เรียก await() รอ | Worker threads เรียก countDown() เมื่อเสร็จ
ตัวอย่าง: รอให้ Services เริ่มต้นเสร็จก่อนเริ่ม App
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class CountDownLatchExample {
public static void main(String[] args) throws InterruptedException {
ExecutorService executor = Executors.newFixedThreadPool(3);
CountDownLatch latch = new CountDownLatch(3); // รอ 3 tasks
// Service 1: Database init
executor.submit(() -> {
try { Thread.sleep(2000); System.out.println("DB ready"); }
catch (InterruptedException e) { Thread.currentThread().interrupt(); }
finally { latch.countDown(); }
});
// Service 2: Cache warmup
executor.submit(() -> {
try { Thread.sleep(1500); System.out.println("Cache ready"); }
catch (InterruptedException e) { Thread.currentThread().interrupt(); }
finally { latch.countDown(); }
});
// Service 3: Config load
executor.submit(() -> {
try { Thread.sleep(1000); System.out.println("Config ready"); }
catch (InterruptedException e) { Thread.currentThread().interrupt(); }
finally { latch.countDown(); }
});
System.out.println("Waiting for services...");
latch.await(); // Block จน count = 0
System.out.println("All services started! Application ready.");
executor.shutdown();
}
}
Output
Waiting for services... Config ready Cache ready DB ready All services started! Application ready.
CyclicBarrier - Reusable Barrier
หลักการ: Threads เรียก await() รอกัน | เมื่อครบจำนวน → รัน barrier action (ถ้ามี) → ปล่อย threads ทั้งหมดพร้อมกัน → reset พร้อมรอบถัดไป
ตัวอย่าง: Parallel Processing แบบ Phases
import java.util.concurrent.BrokenBarrierException;
import java.util.concurrent.CyclicBarrier;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class CyclicBarrierExample {
public static void main(String[] args) {
ExecutorService executor = Executors.newFixedThreadPool(4);
// Barrier สำหรับ 4 threads + barrier action
CyclicBarrier barrier = new CyclicBarrier(4, () ->
System.out.println("=== Phase completed! All threads synced ===")
);
for (int i = 1; i <= 4; i++) {
final int id = i;
executor.submit(() -> {
try {
// Phase 1
System.out.println("Thread " + id + " - Phase 1 start");
Thread.sleep((long) (Math.random() * 1000));
System.out.println("Thread " + id + " - Phase 1 done, waiting...");
barrier.await(); // รอ thread อื่น
// Phase 2
System.out.println("Thread " + id + " - Phase 2 start");
Thread.sleep((long) (Math.random() * 1000));
System.out.println("Thread " + id + " - Phase 2 done, waiting...");
barrier.await(); // รออีกรอบ (reusable!)
// Phase 3
System.out.println("Thread " + id + " - Phase 3 done");
} catch (InterruptedException | BrokenBarrierException e) {
Thread.currentThread().interrupt();
}
});
}
executor.shutdown();
}
}
Output (ตัวอย่าง)
Thread 1 - Phase 1 start Thread 2 - Phase 1 start Thread 3 - Phase 1 start Thread 4 - Phase 1 start Thread 3 - Phase 1 done, waiting... Thread 1 - Phase 1 done, waiting... Thread 4 - Phase 1 done, waiting... Thread 2 - Phase 1 done, waiting... === Phase completed! All threads synced === Thread 3 - Phase 2 start Thread 1 - Phase 2 start ... (ทำซ้ำสำหรับ Phase 2, 3)
สรุป: เลือกอะไรดี?
| สถานการณ์ | เหมาะสม | เหตุผล |
|---|---|---|
| รอ initialization services เริ่มต้นแอป | CountDownLatch | One-shot, main thread รอ workers |
| Parallel algorithm แบบหลาย phases (map-reduce) | CyclicBarrier | Reusable, sync ทุก phase |
| รอ multiple threads ทำงานเสร็จก่อนรวมผล | CountDownLatch | Simple countdown |
| Game loop / Simulation steps | CyclicBarrier | Barrier action ระหว่าง steps |
| ต้องการรัน callback เมื่อทุก thread มาถึง | CyclicBarrier | Constructor รับ Runnable |
Related: Phaser (Java 7+)
Phaser ยืดหยุ่นกว่า CyclicBarrier - รองรับ dynamic registration/deregistration, multiple phases, tiered synchronization