Interpretation of the java synchronization class CountDownLatch

Keywords: Java git github

Synchronization Auxiliary Class:

CountDownLatch is a synchronization assistant class introduced in jdk5, which allows one or more threads to wait until other threads have completed their operations.    

Realization principle:

CountDownLatch is implemented by a counter whose initial value is the number of threads. Every time a thread completes its task, it subtracts 1 from the counter. When the value of the counter is 0, it means that all threads have completed the task. At this time, it waits for the thread on the latch to continue to execute, so as to achieve the purpose of waiting for other threads to complete the task before continuing to execute.

 

CountDownLatch's main methods are:

CountDownLatch is implemented by synchronizer, using AQS state to represent count:

    /**
     * Synchronization control For CountDownLatch.
     * Uses AQS state to represent count.
     */
    private static final class Sync extends AbstractQueuedSynchronizer {
        private static final long serialVersionUID = 4982264981922014374L;

        Sync(int count) {
            setState(count);
        }

        int getCount() {
            return getState();
        }

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

        protected boolean tryReleaseShared(int releases) {
            // Decrement count; signal when transition to zero
            for (;;) {
                int c = getState();
                if (c == 0)
                    return false;
                int nextc = c-1;
                if (compareAndSetState(c, nextc))
                    return nextc == 0;
            }
        }
    }

    private final Sync sync;

  

1. Constructor

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

Create a CountDownLatch by passing in a value that indicates the number of times a thread can recover from the wait state and the countDown method must be called

 

2. countDown method

public void countDown() {
        sync.releaseShared(1);
    }  

Threads call this method to subtract count by 1. When count is 0, this method does nothing. When count is larger than 0, this method is called to subtract 1. When new count is 0, all waiting threads are released.

 

3. await method

(1) No parameters

    public void await() throws InterruptedException {
        sync.acquireSharedInterruptibly(1);
    }

When this method is called, when count is 0, it returns true directly. When count is larger than zero, the thread waits until count becomes 0 or interepted.

(2) with parameters

    public boolean await(long timeout, TimeUnit unit)
        throws InterruptedException {
        return sync.tryAcquireSharedNanos(1, unit.toNanos(timeout));
    }

When this method is invoked, when count is 0, it returns true directly. When count is larger than zero, the thread will wait for a period of time. If the value of count changes to 0, it returns true; when it exceeds the waiting time, it returns false; or when the thread is interrupted during the waiting time, an interrupt exception will be thrown.  

 

CountDownLatch Practice

Drivers and workers, workers have to wait until the driver arrives to load the car. Drivers have to wait until all workers load the goods on the car before they can drive away.

Workers:

public class Worker implements Runnable {

    private String workerCode;

    private CountDownLatch startLatch;
    private CountDownLatch latch;

    Worker(CountDownLatch startLatch, CountDownLatch latch, String workerCode) {
        this.startLatch = startLatch;
        this.latch = latch;
        this.workerCode = workerCode;
    }

    public void run() {
        try {
            startLatch.await();
            doWork();
            latch.countDown();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

    private void doWork() {
        System.out.println("Worker " + workerCode + " is loading goods...");
    }
}

Driver class:

public class Driver {
    public static void main(String[] args) throws InterruptedException {
        CountDownLatch startLatch = new CountDownLatch(1);
        CountDownLatch latch = new CountDownLatch(10);
        ExecutorService executor = Executors.newFixedThreadPool(10);

        for(int i=0; i<10; i++) {
            executor.execute(new Worker(startLatch, latch, "worker" + i));
        }

        System.out.println("Driver is here.");

        startLatch.countDown();

        System.out.println("Workers get to work.");

        latch.await();

        System.out.println("Driver is ready to go.");

        executor.shutdown();
    }
}  

Operation results:

Driver is here.
Workers get to work.
Worker worker0 is loading goods...
Worker worker1 is loading goods...
Worker worker2 is loading goods...
Worker worker3 is loading goods...
Worker worker4 is loading goods...
Worker worker5 is loading goods...
Worker worker7 is loading goods...
Worker worker9 is loading goods...
Worker worker8 is loading goods...
Worker worker6 is loading goods...
Driver is ready to go.

 

For complete engineering code, see git: https://github.com/xuweijian/CountDownLatch.git

Posted by wildncrazyath3rt on Sun, 02 Jun 2019 12:49:26 -0700