Java中使用CountDownLatch进行多线程同步

CountDownLatch介绍

在前面的Java学习笔记中,总结了Java中进行多线程同步的几个方法:java

一、synchronized关键字进行同步。编程

二、Lock锁接口及其实现类ReentrantLock、ReadWriteLock锁实现同步。网络

三、信号量Semaphore实现同步。多线程

其中,synchronized关键字和Lock锁解决的是多个线程对同一资源的并发访问问题。信号量Semaphore解决的是多副本资源的共享访问问题。并发

今天,来学习一下Java中的另一个多线程同步辅助类:CountDownLatch。官方文档对CountDownLatch的解释是:在完成一组正在其余线程中执行的操做以前,它容许一个或多个线程一直等待。也就是说,CountDownLatch控制某个或者多个线程,让它们等待多个线程完成某项任务后,再启动。CountDownLatch主要是用来同步多个任务的执行,区别于其余的synchronized关键字,锁,信号量是用来同步共享资源的。ide

CountDownLatch实现原理简介:

CountDownLatch内部维护一个计数器,计数器的值为待完成的任务数N,须要等待这N个任务完成的线程调用CountDownLatch的await()方法使本身进入休眠等待状态。函数

当某一个任务线程完成某一个任务后调用CountDownLatch的countDown()方法来表示本身的任务已完成,此时CountDownLatch的计数器值减1,当全部的任务完成式,计数器的值为0。当计数器值为0时,CountDownLatch将唤醒全部因await()方法进入休眠的线程。学习

CountDownLatch的使用:

CountDownLatch的使用主要有3点:this

一、CountDownLatch的声明及初始化,在初始化时须要指定等待完成的任务数。spa

二、某一个任务完成时调用CountDownLatch的countDown()方法,向CountDownLatch报告本身的任务已经完成,

三、须要等待任务完成的线程调用CountDownLatch的await()方法,调用后该线程将进入休眠,并在全部任务数完成后CountDownLatch的计数器值为0时,因await()方法进行休眠的线程将被唤醒。

在此本人在Java 7并发编程实战手册该书中的CountDownLatch使用示例的基础上作了部分改进,来演示CountDownLatch的使用详情:

模拟10个参会者和一个主持人参加的一个会以,每一个参会者及主持人须要等待其余的参会者均到场签到以后,才能开始会以并发言。为此,先建立一个会以管理的类VideoConference,其提供一个arrive()方法供参会者调用来进行签到。会议管理的拥有者是主持人,其等待每一个参会者的签到:

public class VideoConference implements  Runnable{
    private final CountDownLatch countDownLatch;
    private int number;
    public VideoConference(int number) {
        this.number = number;
        this.countDownLatch = new CountDownLatch(number);//使用Number初始化其内部的计数器,当初始化完成后,不能再次初始化
    }
    public void arrive(String name){
        //每一个须要同步的任务,在任务完成时,须要调用该方法
        countDownLatch.countDown();//countDownLatch内部的计数器减1
        System.out.print("arrive:"+name+"\n");
        try{
            countDownLatch.await();//await方法是线程进入休眠,当countDownLatch计数器为0时,将被唤醒
            //线程被唤醒,在这里能够执行一系列任务
            System.out.print("name:"+name + " say:let's start..." +"\n");
        }catch (InterruptedException e){
            e.printStackTrace();
        }
    }
    public void run(){
        System.out.print("has arrive:"+(number-countDownLatch.getCount())+"\n");
        try{
            countDownLatch.await();//await方法是线程进入休眠,当countDownLatch计数器为0时,将被唤醒
            //线程被唤醒,在这里能够执行一系列任务
            System.out.print("all arrived:"+(number-countDownLatch.getCount())+"\n");
        }catch (InterruptedException e){
            e.printStackTrace();
        }
    }
}
建立一个参会者类Participant:

public class Participant implements  Runnable{
    private VideoConference videoConference;
    private String name;

    public Participant(String name, VideoConference videoConference) {
        this.name = name;
        this.videoConference = videoConference;
    }
    public void run(){
        try {
            //do something
            Thread.sleep(50);
            //
            videoConference.arrive(name);
        }catch (InterruptedException e){
            e.printStackTrace();
        }
    }

    public static void main(String[] args){
        VideoConference videoConference = new VideoConference(10);
        Thread videoThread = new Thread(videoConference);
        videoThread.start();
        for(int i=0; i<10; i++){
            Thread thread = new Thread(new Participant("participant:"+i,videoConference));
            thread.start();
        }
    }
}
Participant类中的main函数首先建立了一个须要10个参会者参加的一个会议,以后,建立了10个参会者并逐个签到,在10个参会者都签到以后,每一个参会者及主持人将被"唤醒"并发言。

总结:

CountDownLatch类解决的是多线程间的同步等待、任务协调问题,应用在如在启动某个程序的主功能前,须要前置完成配置环境检查、网络检查等多个子任务等相似的场景。在Java中,除了使用CountDownLatch来实现多线程间的同步等待之外,还可使用栅栏技术CyclicBarrier来实现多线程间的同步等待、任务协调。

相关文章
相关标签/搜索