Detailed Explanation of CountDownLatch, CyclicBarrier, and Semaphore in Java

Detailed Explanation of CountDownLatch, CyclicBarrier, and Semaphore in Java

1. Basic Concepts and Roles

CountDownLatch, CyclicBarrier, and Semaphore are commonly used synchronization utility classes in the JUC package, designed to coordinate the execution order among multiple threads or manage resource allocation:

  • CountDownLatch: Allows one or more threads to wait for other threads to complete their operations before proceeding.
  • CyclicBarrier: Enables a group of threads to wait for each other; once all threads reach the barrier point, they continue execution simultaneously. It is reusable.
  • Semaphore: Controls the number of threads that can access a specific resource concurrently, implementing rate limiting through permits.

2. Detailed Explanation of CountDownLatch

Core Mechanism

  • Initialize with a specified counter (e.g., new CountDownLatch(3)).
  • The counter decrements by 1 when a thread calls countDown(); threads calling await() will block until the counter reaches zero.

Use Cases

  • The main thread waits for multiple child threads to complete tasks before proceeding (e.g., aggregating results after parallel computation).
  • Waiting for all dependent components to initialize during service startup.

Example Code

CountDownLatch latch = new CountDownLatch(2);

// Child threads decrement the counter after completing tasks
new Thread(() -> {
    System.out.println("Task 1 completed");
    latch.countDown();
}).start();

new Thread(() -> {
    System.out.println("Task 2 completed");
    latch.countDown();
}).start();

// Main thread waits for all tasks to complete
latch.await();
System.out.println("All tasks completed, main thread continues");

Characteristics: The counter cannot be reset; it is for one-time use only.


3. Detailed Explanation of CyclicBarrier

Core Mechanism

  • Initialize with a specified number of threads (e.g., new CyclicBarrier(3)) and an optional barrier action (Runnable).
  • Threads block when calling await() until the specified number of threads reach the barrier point; then all threads continue execution simultaneously.

Use Cases

  • Synchronization in multi-phase tasks (e.g., waiting for all threads to be ready at each stage in parallel computation).
  • Simulating concurrent testing (multiple threads triggering operations simultaneously).

Example Code

CyclicBarrier barrier = new CyclicBarrier(3, () -> {
    System.out.println("All threads reached the barrier, executing barrier action");
});

for (int i = 0; i < 3; i++) {
    new Thread(() -> {
        System.out.println(Thread.currentThread().getName() + " reached the barrier");
        try {
            barrier.await(); // Wait for other threads
        } catch (Exception e) {
            e.printStackTrace();
        }
        System.out.println(Thread.currentThread().getName() + " continues execution");
    }).start();
}

Characteristics: The counter can be reset (via the reset() method), supporting reuse.


4. Detailed Explanation of Semaphore

Core Mechanism

  • Initialize with a specified number of permits (e.g., new Semaphore(3)).
  • Threads acquire permits via acquire() (blocking if no permits are available) and release permits via release().

Use Cases

  • Limiting concurrent access to resources (e.g., database connection pools, interface rate limiting).
  • Controlling the submission rate of tasks in a thread pool.

Example Code

Semaphore semaphore = new Semaphore(2); // Allow 2 threads to access concurrently

for (int i = 0; i < 5; i++) {
    new Thread(() -> {
        try {
            semaphore.acquire(); // Acquire a permit
            System.out.println(Thread.currentThread().getName() + " occupied resource");
            Thread.sleep(2000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            semaphore.release(); // Release the permit
            System.out.println(Thread.currentThread().getName() + " released resource");
        }
    }).start();
}

Characteristics: Supports fair/non-fair modes; permits can be dynamically increased or decreased.


5. Comparison of the Three

Feature CountDownLatch CyclicBarrier Semaphore
Counter Resettable? No (one-time use) Yes (reusable) Yes (permits recyclable)
Core Role Wait for other threads to complete Threads wait for each other Control resource access quantity
Key Methods await()/countDown() await() acquire()/release()
Suitable Scenarios Master-slave collaboration Multi-phase synchronization Resource pools, rate limiting

6. Considerations

  1. CountDownLatch: await() can be set with a timeout to avoid indefinite waiting.
  2. CyclicBarrier: The barrier action is executed by the last thread arriving at the barrier.
  3. Semaphore: The release() method can be called in any thread, even without calling acquire() first (which may cause the number of permits to exceed the initial value).

By appropriately selecting these three tools, thread synchronization and resource control issues can be efficiently resolved.