Use of CountDownLatch class

Description of CountDownLatch

JDk1.5 provides a very useful package, Concurrent package. This package is mainly used to operate some concurrent operations and provide some concurrent classes, which can be easily applied in projects.

Before JDK1.5, concurrent operations were used to operate multiple threads through Thread and Runnable; but after JDK1.5, a very convenient thread pool (ThreadExecutorPool) was provided, and the main code was completed by Daniel Doug Lea. In the era of jdk1.4, since the built-in support for multi-threaded programming in the java language was relatively basic and limited, he wrote this, because it was too good, so it was added to jdk. This article will introduce the CountDownLatch class under the Concurrent package.

The CountDownLatch class is located in the java.util.concurrent package, and it can be used to implement counter-like functions. For example, there is a task A, which can only be executed after the other 4 tasks are executed. At this time, CountDownLatch can be used to realize this function. CountDownLatch is implemented by a counter whose initial value is the number of threads. Every time a thread completes its task, the value of the counter is decremented by 1. When the counter value reaches 0, it indicates that all threads have completed the task, and then the thread waiting on the latch can resume the task.

The count value (count) in the constructor is actually the number of threads that the lock needs to wait for. This value can only be set once, and CountDownLatch does not provide any mechanism to reset the count value.

The first interaction with CountDownLatch is that the main thread waits for other threads. The main thread must call the CountDownLatch.await() method immediately after starting other threads. This way the main thread's operations will block on this method until other threads complete their respective tasks.

The other N threads must refer to the latch object because they need to notify the CountDownLatch object that they have completed their respective tasks. This notification mechanism is accomplished through the CountDownLatch.countDown() method; each time this method is called, the count value initialized in the constructor is decremented by 1. So when N threads all call this method, the value of count is equal to 0, and then the main thread can resume executing its own tasks through the await() method.


CountDownLatch code example

Let's use an example to demonstrate the use of CountDownLatch. In this example, we simulate a dangerous chemical vehicle monitoring center. It starts n threads at the beginning, these threads will check whether the chemical vehicle at the dispatch station can start, and notify the blocking, and the start class has been waiting on the blocking. Once it is verified and checked that the chemical vehicles at all dispatch stations can depart normally, the start-up class will resume execution.

DangerCenter class, this class is a Runnable, which is responsible for the inspection of chemical vehicles in all dispatching stations, and belongs to a monitoring center. code show as below:

package org.zero01.zk.countdown;

import java.util.concurrent.CountDownLatch;

/**
 * 抽象类,用于演示 危险品化工车监控中心 统一检查
 */
public abstract class DangerCenter implements Runnable {

    private CountDownLatch countDown;       // 计数器
    private String station;                 // 调度站
    private boolean ok;                     // 调度站针对当前自己的站点进行检查,是否检查ok的标志

    public DangerCenter(CountDownLatch countDown, String station) {
        this.countDown = countDown;
        this.station = station;
        this.ok = false;
    }

    public void run() {
        try {
            check();
            ok = true;
        } catch (Exception e) {
            e.printStackTrace();
            ok = false;
        } finally {
            if (countDown != null) {
                countDown.countDown();
            }
        }
    }

    /**
     * 检查危化品车
     * 蒸罐
     * 汽油
     * 轮胎
     * gps
     * ...
     */
    public abstract void check();

    public CountDownLatch getCountDown() {
        return countDown;
    }
    public void setCountDown(CountDownLatch countDown) {
        this.countDown = countDown;
    }
    public String getStation() {
        return station;
    }
    public void setStation(String station) {
        this.station = station;
    }
    public boolean isOk() {
        return ok;
    }
    public void setOk(boolean ok) {
        this.ok = ok;
    }
}

StationBeijing class, this class is used as a dispatching station. This class inherits DangerCenter and implements the check() method. Each dispatching station checks its own vehicle. code show as below:

package org.zero01.zk.countdown;

import java.util.concurrent.CountDownLatch;

public class StationBeijing extends DangerCenter {

    public StationBeijing(CountDownLatch countDown) {
        super(countDown, "北京调度站");
    }

    @Override
    public void check() {
        System.out.println("正在检查 [" + this.getStation() + "]...");

        try {
            Thread.sleep(2000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        System.out.println("检查 [" + this.getStation() + "] 完毕,可以发车~");
    }
}

StationShandongChangchuan and StationJiangsuSanling are the same as StationBeijing except for the station name and sleep time, so they are omitted here.

CheckStartUp class, this class is a main startup class, it is responsible for initializing the blocking, and then waiting until all the vehicles in the dispatch station have been detected. code show as below:

package org.zero01.zk.countdown;

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.Executor;
import java.util.concurrent.Executors;

public class CheckStartUp {

    private static List<DangerCenter> stationList;
    private static CountDownLatch countDown;

    public CheckStartUp() {
    }

    public static boolean checkAllStations() throws Exception {

        // 初始化3个调度站
        countDown = new CountDownLatch(3);

        // 把所有站点添加进list
        stationList = new ArrayList<DangerCenter>();
        stationList.add(new StationBeijing(countDown));
        stationList.add(new StationJiangsuSanling(countDown));
        stationList.add(new StationShandongChangchuan(countDown));

        // 使用线程池
        Executor executor = Executors.newFixedThreadPool(stationList.size());

        for (DangerCenter center : stationList) {
            executor.execute(center);
        }

        // 等待线程执行完毕
        countDown.await();

        for (DangerCenter center : stationList) {
            if (!center.isOk()) {
                return false;
            }
        }

        return true;
    }

    public static void main(String[] args) throws Exception {
        boolean result = CheckStartUp.checkAllStations();
        System.out.println("监控中心针对所有危化品调度站点的检查结果为:" + result);
    }
}

Run the CheckStartUp class, and the console prints the result as follows:

正在检查 [北京调度站]...
正在检查 [山东长川调度站]...
正在检查 [江苏三林调度站]...
检查 [山东长川调度站] 完毕,可以发车~
检查 [江苏三林调度站] 完毕,可以发车~
检查 [北京调度站] 完毕,可以发车~
监控中心针对所有危化品调度站点的检查结果为:true

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=324973372&siteId=291194637