java.util.concurrent.CountDownLatch 使用

1. 概述

   CountDownLatch是java的一个并发工具(java.util.concurrent.CountDownLatch), 闭锁。

   主要功能是阻塞调用其await()方法的线程,直到其他线程调用countDown()使得count(计数器)变为0时立即从await返回

2. 主要应用场景

   2.1 主线程等待各子线程完成子任务再开始执行

  

package countDownLatch;

import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.concurrent.CountDownLatch;

public class CountDownLatchTestAllDoneNotifyMain {

    
    static CountDownLatch latch = new CountDownLatch(3);
    public static void main(String[] args) throws InterruptedException{
        System.out.println("Time point one:"+new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date()));
        new Thread(){
            public void run(){
                try {
                    Thread.sleep(3000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println("sub task 1 done");
                latch.countDown();
            }
        }.start();
        new Thread(){
            public void run(){
                try {
                    Thread.sleep(2000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println("sub task 2 done");
                latch.countDown();
            }
        }.start();
        new Thread(){
            public void run(){
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println("sub task 3 done");
                latch.countDown();//
            }
        }.start();
        
        latch.await();//阻塞 直到构造的3变为0
        System.out.println("Time point two:"+new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date()));
        System.out.println("sub task all done, and main task running.....");
    }
}

2.2 多个线程等待(await),被一个线程同时唤醒(countDown), 初始count为1

package countDownLatch;

import java.util.concurrent.CountDownLatch;

public class CountDownLatchTestOneDoneNotifyAll {

    private static CountDownLatch latch = new CountDownLatch(1);
    public static void main(String[] args) throws InterruptedException {
        for(int i=0; i<3; i++){
            new Thread(){
                public void run(){
                    System.out.println(Thread.currentThread().getName()+" waiting...");
                    try {
                        latch.await();
                        System.out.println(Thread.currentThread().getName()+" running");
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }.start();
        }
        System.out.println("Main thread do something...");
        Thread.sleep(2000);
        System.out.println("Sub Thread begin to run...");
        latch.countDown();
    }
}

 两种场景一起测试

package countDownLatch;

import java.util.concurrent.CountDownLatch;

public class Driver {

    public static void main(String[] args) throws InterruptedException {
        CountDownLatch startSignal = new CountDownLatch(1);
        CountDownLatch doneSignal = new CountDownLatch(3);
        for(int i=0; i<3; i++) {
            new Thread(new Worker(startSignal, doneSignal)).start();
        }
        doSomething();
        startSignal.countDown();
        doSomething();
        doneSignal.await();
    }

    private static void doSomething() {
        // TODO Auto-generated method stub
        
    }
    
}

class Worker implements Runnable{
    private CountDownLatch startSignal;
    private CountDownLatch doneSignal;
    Worker(CountDownLatch startSignal, CountDownLatch doneSignal){
        this.startSignal = startSignal;
        this.doneSignal = doneSignal;
    }
    public void run(){
        try {
            startSignal.await();
            doWork();
            doneSignal.countDown();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
    private void doWork() {
        
    }
}

 3. note

    3.1 countDown()可以被一个线程执行多次,count随之减1;

    3.2 在直接创建子线程使用时可以使用Thread.join()达到主线程等待子线程忙完在执行的效果,

          在使用线程池等情境下, 没法直接操作线程, 可以使用CountDownLatch

原文地址:https://www.cnblogs.com/rocky-fang/p/6763396.html