Location>code7788 >text

A thorough understanding of the JUC toolkit CountDownLatch design concepts and underlying principles

Popularity:625 ℃/2024-11-09 10:50:25

CountDownLatch is a Java concurrency package () in a synchronization helper class that allows one or more threads to wait for a set of operations to complete.

I. Design Concept

CountDownLatch is based on the AQS (AbstractQueuedSynchronizer) implementation. The core idea is thatMaintaining a countdownThe threads that are waiting will continue to execute each time the countdown decreases to zero. Its main design goal is to allow multiple threads to coordinate the completion of a set of tasks.

1. Constructors and counters

public CountDownLatch(int count) {
    if (count < 0) throw new IllegalArgumentException("count < 0");
     = new Sync(count);
}

tectonic (geology)CountDownLatch incomingcount determines the initial value of the counter. This counter controls the release of the thread.

2. Core operations supported by AQS

AQS YesCountDownLatch The basis for this is through customizing the inner classSync Realization.Sync inherits from AQS and provides the necessary methods. The following are the key operations:

  • acquireShared(int arg): If the counter value is zero, it means that all tasks have been completed and the thread will be licensed.
  • releaseShared(int arg): Each call tocountDown()The AQS will reduce the counter, and when the counter drops to zero, the AQS will release all waiting threads.

3. Realization details

  • countDown(): CallreleaseShared() Decreases the counter and notifies the waiting thread.
  • await(): CallacquireSharedInterruptibly(1)If the counter is non-zero, it blocks and waits.

II. Underlying principles

CountDownLatch The core of the program is based onAbstractQueuedSynchronizer(AQS) to manage counter state.AQS is the basis for many synchronization tools in JUC, enabling thread management and scheduling through a synchronized queue in exclusive/shared mode.CountDownLatch The use of AQSshared locking mechanismto control multiple threads waiting for a condition.

1. AQS sharing model

AQS is designed with two modes of synchronization:Exclusive mode(exclusive) andshared model(shared)。CountDownLatch Use the shared model:

  • Exclusive mode: Only one thread can hold the lock at a time, as inReentrantLock
  • shared model: Allows multiple threads to share lock state, such as theSemaphore cap (a poem)CountDownLatch

CountDownLatch (used form a nominal expression)await() cap (a poem)countDown() method corresponds to the AQSacquireShared() cap (a poem)releaseShared() Operation.acquireShared() Will check the synchronization status (counter value), if the status is zero then return immediately, otherwise block the current thread and enter the waiting queue.releaseShared() Used to reduce the counter and wake up all waiting threads.

2. Design of Sync internal classes

CountDownLatch Through a private inner classSync to implement the synchronization logic.Sync inherited fromAQSand rewritetryAcquireShared(int arg) cap (a poem)tryReleaseShared(int arg) Methods.

static final class Sync extends AbstractQueuedSynchronizer {
    Sync(int count) {
        setState(count);
    }

    protected int tryAcquireShared(int acquires) {
        return (getState() == 0) ? 1 : -1;
    }

    protected boolean tryReleaseShared(int releases) {
        // spin-down counter
        for (;;) {
            int c = getState();
            if (c == 0)
                return false;
            int nextc = c - 1;
            if (compareAndSetState(c, nextc))
                return nextc == 0;
        }
    }
}
  • tryAcquireShared(int): Returns 1 (successful lock acquisition) when the counter is zero, otherwise returns -1 (blocking).
  • tryReleaseShared(int): Each timecountDown() Decreases the counter value and returns when the counter reaches zerotruethat wakes up all blocking threads.

3. CAS operations ensure thread safety

tryReleaseShared method uses CAS (compare-and-set) to update the counter, avoiding the overhead of locks.CAS operations are performed by CPU primitives such ascmpxchg instructions) support, enabling efficient non-blocking operations. This design ensures that thecountDown() of thread safety, allowing multiple threads to concurrently reduce the counter.

4. Internal ConditionObject

CountDownLatch reuse is not supported because AQS'sConditionObject is designed as a single trigger mode. Once the counter drops to zero, theCountDownLatch It can't be reset, you can only release all threads without setting the initial counter value again. This is the root cause of its non-reusability.

III. Application scenarios

  1. Waiting for multi-threaded tasks to completeCountDownLatch Commonly used in scenarios where you need to wait for a group of threads to complete their tasks before continuing, such as batch processing tasks.
  2. Parallel execution re-summarization: In some data analysis or computationally intensive tasks, the task is split into multiple subtasks to be executed in parallel, and the main thread waits for all subtasks to complete before summarizing the results.
  3. Multi-service dependency coordination: When a service depends on multiple other services, you can use theCountDownLatch to synchronize calls to individual services and ensure that all dependent services are ready before executing the main task.

IV. Sample code

The following example shows how to use theCountDownLatch Implement a mechanism for a concurrent task to wait for all subtasks to complete.

import ;

public class CountDownLatchExample {
    private static final int TASK_COUNT = 5;
    private static CountDownLatch latch = new CountDownLatch(TASK_COUNT);

    public static void main(String[] args) throws InterruptedException {
        for (int i = 0; i < TASK_COUNT; i++) {
            new Thread(new Task(i + 1, latch)).start();
        }
        
        // The main thread waits for all tasks to complete
        ();
        ("All tasks have been completed,Continuation of main thread tasks");
    }

    static class Task implements Runnable {
        private final int taskNumber;
        private final CountDownLatch latch;

        Task(int taskNumber, CountDownLatch latch) {
             = taskNumber;
             = latch;
        }

        @Override
        public void run() {
            try {
                ("subtask " + taskNumber + " commence");
                ((int) (() * 1000)); // Simulation of task execution time
                ("subtask " + taskNumber + " fulfillment");
            } catch (InterruptedException e) {
                ().interrupt();
            } finally {
                (); // fulfillment一个任务,Counter minus one
            }
        }
    }
}

V. Comparison with other synchronization tools

1. CyclicBarrier

Principles and Uses

  • CyclicBarrier It also allows a group of threads to wait for each other until all threads reach the barrier point.
  • It is suitable for use inmultistage taskmaybeStaged Convergence, such as summarizing results at each stage when dealing with chunked calculations.

underlying implementation

  • CyclicBarrier Internally throughReentrantLock cap (a poem)Condition implementation, the barrier count can be reset, thus supporting recycling.

Comparison with CountDownLatch

  • CyclicBarrier (used form a nominal expression)reusabilitymakes it suitable for repetitive synchronization scenarios, whileCountDownLatch It's a one-time thing.
  • CountDownLatch More flexible, allowing arbitrary thread callscountDown(), suitable for distributed tasks.CyclicBarrier Requires the specified thread to reach the barrier.

2. Semaphore

Principles and Uses

  • Semaphore mainly used forControlling access to resourcesof concurrency, such as limiting access to a database connection pool.

underlying implementation

  • Semaphore A shared schema implementation based on AQS, similar to theCountDownLatchThe "License" number is the number of "licenses" that are allowed to control the resources.

Comparison with CountDownLatch

  • Semaphore Licenses can be dynamically increased/decreased, whileCountDownLatch Only decreasing.
  • Semaphore suitable for controlling access restrictions, whileCountDownLatch Used for synchronizing point countdown.

3. Phaser

Principles and Uses

  • Phaser beCyclicBarrier enhancement that allows the number of participating threads to be dynamically adjusted.
  • Ideal for multi-stage task synchronization with the ability to increase or decrease participating threads at any time.

underlying implementation

  • Phaser An internal counter is included to manage the participating threads in the current phase, allowing tasks to be dynamically registered or logged off.

Comparison with CountDownLatch

  • Phaser Better suited to complex scenarios, with the ability to flexibly control stages and participation threads;CountDownLatch has a simple structure and can only be used for one-time synchronization.
  • Phaser is designed to be more complex for long, multi-threaded coordination tasks, while theCountDownLatch Better for simple tasks waiting.

4. Summary

CountDownLatch is a lightweight, non-reusable countdown synchronizer for simple one-time thread coordination. Its AQS-based shared locking implementation allows for efficient concurrency in thread waiting and counter updating. AlthoughCountDownLatch Not reusable, but its clean design makes it especially suitable for scenarios where you need to wait for a multi-threaded task to complete.

Compared to other JUC tools:

  • CyclicBarrier It is more suitable for multi-stage synchronization and stage summarization tasks.
  • Semaphore Suitable for resource access control with a controlled amount of licenses.
  • Phaser Higher flexibility for dynamic participation in threads, complex multi-stage tasks.

Choosing the right synchronization tool depends on the nature of the task, the dynamics of thread involvement, and the need to reuse synchronization controls.