一.场景引入
教师里有很多学生,比如说有7个,其中一个是班长,他负责在全员离开后关闭大门,现在要实现一个程序,其中包括main线程在内有七个线程,main是班长。
需求是:班长要在所有人都离开教室之后才关闭大门,也就是说main线程需要在所有线程运行完之后才打印这条语句
public static void main(String[] args) {
for (int i = 1; i <=6 ; i++) {
new Thread(()->{
System.out.println(Thread.currentThread().getName()+"\t离开教室。");
},String.valueOf(i)).start();
}
System.out.println("班长离开,关门。。。");
}
这样能实现我们的要求吗?:
"C:\Program Files\Java\jdk1.8.0_181\bin\java.exe" "-javaagent:D:\idea\IntelliJ IDEA 2019.2.3\lib\idea_rt.jar=52240:D:\idea\IntelliJ IDEA 2019.2.3\bin" -Dfile.encoding=UTF-8 -classpath "C:\Program Files\Java\jdk1.8.0_181\jre\lib\charsets.jar;C:\Program Files\Java\jdk1.8.0_181\jre\lib\deploy.jar;C:\Program Files\Java\jdk1.8.0_181\jre\lib\ext\access-bridge-64.jar;C:\Program Files\Java\jdk1.8.0_181\jre\lib\ext\cldrdata.jar;C:\Program Files\Java\jdk1.8.0_181\jre\lib\ext\dnsns.jar;C:\Program Files\Java\jdk1.8.0_181\jre\lib\ext\jaccess.jar;C:\Program Files\Java\jdk1.8.0_181\jre\lib\ext\jfxrt.jar;C:\Program Files\Java\jdk1.8.0_181\jre\lib\ext\localedata.jar;C:\Program Files\Java\jdk1.8.0_181\jre\lib\ext\nashorn.jar;C:\Program Files\Java\jdk1.8.0_181\jre\lib\ext\sunec.jar;C:\Program Files\Java\jdk1.8.0_181\jre\lib\ext\sunjce_provider.jar;C:\Program Files\Java\jdk1.8.0_181\jre\lib\ext\sunmscapi.jar;C:\Program Files\Java\jdk1.8.0_181\jre\lib\ext\sunpkcs11.jar;C:\Program Files\Java\jdk1.8.0_181\jre\lib\ext\zipfs.jar;C:\Program Files\Java\jdk1.8.0_181\jre\lib\javaws.jar;C:\Program Files\Java\jdk1.8.0_181\jre\lib\jce.jar;C:\Program Files\Java\jdk1.8.0_181\jre\lib\jfr.jar;C:\Program Files\Java\jdk1.8.0_181\jre\lib\jfxswt.jar;C:\Program Files\Java\jdk1.8.0_181\jre\lib\jsse.jar;C:\Program Files\Java\jdk1.8.0_181\jre\lib\management-agent.jar;C:\Program Files\Java\jdk1.8.0_181\jre\lib\plugin.jar;C:\Program Files\Java\jdk1.8.0_181\jre\lib\resources.jar;C:\Program Files\Java\jdk1.8.0_181\jre\lib\rt.jar;C:\Users\李肇京\IdeaProjects\JUC\out\production\JUC" JUC_01_SellTicket.HelperClasses.CountDownLatchDemo
班长离开,关门。。。
1 离开教室。
4 离开教室。
3 离开教室。
2 离开教室。
5 离开教室。
6 离开教室。
Process finished with exit code 0
你可以多试几次,可能会出现符合条件的情况,但是这并不是稳定情况,不能满足我们的需求。
二.CountDownLatch介绍
- countDownLatch存在于java.util.cucurrent包下,是JUC辅助类的一种
- countDownLatch这个类实现的功能是:使一个线程等待其他线程各自执行完毕后再执行
- 是通过一个计数器来实现的,计数器的初始值是线程的数量。每当一个线程执行完毕后,计数器的值就-1,当计数器的值为0时,表示所有线程都执行完毕,然后在闭锁上等待的线程就可以恢复工作了
怎么加在我们的代码中?:
public static void main(String[] args) throws InterruptedException {
//1.创建对象
CountDownLatch countDownLatch = new CountDownLatch(6);
for (int i = 1; i <=6 ; i++) {
new Thread(()->{
System.out.println(Thread.currentThread().getName()+"\t离开教室。");
countDownLatch.countDown();//2.计数
},String.valueOf(i)).start();
}
countDownLatch.await();//main线程等待
System.out.println("班长离开,关门。。。");
}
三.原理
CountDownLatch中有三个关键的方法
//调用await()方法的线程会被挂起,它会等待直到count值为0才继续执行
public void await() throws InterruptedException { };
//和await()类似,只不过等待一定的时间后count值还没变为0的话就会继续执行
public boolean await(long timeout, TimeUnit unit) throws InterruptedException { };
//将count值减1
public void countDown() { };
CountDownLatch只有一个构造器:
//参数count为计数值
public CountDownLatch(int count) { };
它要求我们提供一个count用来计数,也就是用来规定有几个线程是要先执行的,这里我们有6个学生要离开教室,所以传入6.
由于主线程打印之前有一条语句countDownLatch.await(),所以main线程不会直接打印,而是等待循环内部将计数器逐渐减少,知道其值为0,此时main继续执行。这样就完成了我们的需求。