你是否遇到这这样一种状况,咱们要举行一个视频会议,有若干的参会人员,须要等待全部的人员到齐后视频会议才能开始。java
为了解决这个问题,Java API提供了一个线程同步辅助类CountDownLatch,使用这个辅助类可让线程等待其它线程完成一组操做后才能执行,不然就一直等待。这个类使用一个整形参数来初始化,这个整形参数表明着等待其余线程的数量,使用await()方法让线程开始等待其余线程执行完毕,每个线程执行完毕后后调用countDown()方法,这个方法会让CountDownLatch内部的计数器减1,当计数器变为0的时候,CountDownLatch类将唤醒全部调用await()方法并进入WAITING状态线程。并发
下面咱们来完成这个视频会议的例子:dom
建立视频会议线程类VideoConference,并声明一个CountDownLatch属性controller来控制视频会议线程等待全部参会者到齐。会议线程启动后会调用await()方法并进入等待状态,每个参会者到达后代用arrive()方法,并把controller中的计数器减1,当计数器等于0的时候会议线程继续执行。ide
public class VideoConference implements Runnable{ private final CountDownLatch controller; public VideoConference(int number) { controller = new CountDownLatch(number); } public void arrive(String name) { System.out.printf("%s has arrived.\n", name); controller.countDown(); System.out.printf("VideoConference: Waiting for %d participants.\n", controller.getCount()); } @Override public void run() { System.out.printf("VidwoConference: Initialization: %d participants.\n", controller.getCount()); try { controller.await(); System.out.printf("VidwoConference: All the participants have come.\n"); System.out.printf("VidwoConference: Let's start..."); } catch (InterruptedException e) { e.printStackTrace(); } } }
建立参会者线程类Participant,这个类持有会议类的引用,启动后用一个随机休眠时间来模拟与会者到达所需的时间,休眠结束后代用会议类的arrive(name)方法告诉会议类,与会者到达并把CountDownLatch计数器减1。this
public class Participant implements Runnable{ private String name; private VideoConference videoConference; public Participant(String name, VideoConference videoConference) { this.name = name; this.videoConference = videoConference; } @Override public void run() { long duration = (long) (Math.random() * 10); try { TimeUnit.SECONDS.sleep(duration); } catch (InterruptedException e) { e.printStackTrace(); } videoConference.arrive(name); } }
实现主方法类,这里咱们建立并移动一个视频会议,规定参会者有10我的。而后咱们启动10个参会者线程,当全部参会者都到达后,视频会议开始执行。线程
public class Main { public static void main(String[] args) { VideoConference videoConference = new VideoConference(10); Thread threadConference = new Thread(videoConference); threadConference.start(); Thread[] threads = new Thread[10]; for (int i = 0; i < 10; i++) { threads[i] = new Thread(new Participant("P-" + i, videoConference)); } for (int i = 0; i < 10; i++) { threads[i].start(); } } }
查看控制台日志,咱们看到每次有一个参会者到达均可以调用getCount()方法来获取计数器的值。日志
VidwoConference: Initialization: 10 participants. P-0 has arrived. VideoConference: Waiting for 9 participants. P-4 has arrived. VideoConference: Waiting for 8 participants. P-2 has arrived. VideoConference: Waiting for 7 participants. P-5 has arrived. VideoConference: Waiting for 6 participants. P-8 has arrived. VideoConference: Waiting for 5 participants. P-3 has arrived. VideoConference: Waiting for 4 participants. P-6 has arrived. VideoConference: Waiting for 3 participants. P-1 has arrived. VideoConference: Waiting for 2 participants. P-7 has arrived. VideoConference: Waiting for 1 participants. P-9 has arrived. VideoConference: Waiting for 0 participants. VidwoConference: All the participants have come. VidwoConference: Let's start...
注意,CountDownLatch并非用来保护共享资源同步访问的,而是用来控制并发线程等待的。而且CountDownLatch只容许进入一次,一旦内部计数器等于0,再调用这个方法将不起做用,若是还有第二次并发等待,你还得建立一个新的CountDownLatch。code