任何线程,通常是应用程序的主线程,调用CountDownLatch.await()
将等到计数达到零或被另一个线程中断。所有其他线程都需要CountDownLatch.countDown()
在完成或准备好后通过调用来倒计时。
一旦计数达到零,等待线程就会继续。其中一个缺点/优点CountDownLatch
是它不可重复使用:一旦计数达到零,就不能再使用CountDownLatch
了。
使用CountDownLatch
当一个线程(比如主线程),需要等待一个或多个线程来完成,才能继续处理。
CountDownLatch
Java 中使用的典型示例是服务器端核心Java应用程序,它使用服务体系结构,其中多个服务由多个线程提供,并且应用程序无法在所有服务成功启动之前开始处理。
package CountDownLatch_6;
import java.util.concurrent.CountDownLatch;
public class Manager {
public static void main(String[] args) throws InterruptedException {
CountDownLatch latch=new CountDownLatch(2);
MyDevTeam devTeam=new MyDevTeam(latch, "dev1");
MyDevTeam devTeam2=new MyDevTeam(latch, "dev2");
devTeam.start();
devTeam2.start();
latch.await();
MyQATeam qa=new MyQATeam();
qa.start();
}
}
class MyDevTeam extends Thread{
CountDownLatch latch;
public MyDevTeam(CountDownLatch latch,String name ) {
// TODO Auto-generated constructor stub
super(name);
this.latch=latch;
}
public void run(){
System.out.println("任务分配给"+currentThread().getName());
try {
Thread.sleep(2000);
System.out.println(currentThread().getName()+"开始执行");
latch.countDown();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println("任务已经被"+currentThread().getName()+"执行完毕");
}
}
class MyQATeam extends Thread{
public void run(){
System.out.println("任务分配给qa执行");
System.out.println("qa完成该任务");
}
}
执行结果:
任务分配给dev2
任务分配给dev1
dev2开始执行
任务已经被dev2执行完毕
dev1开始执行
任务已经被dev1执行完毕
任务分配给qa执行
qa完成该任务
JOIN的限制: 以上示例也可以通过JOIN实现,但JOIN不能在两种情况下使用:
- 当我们使用ExecutorService而不是Thread类来创建线程时。
- 修改以上示例,管理员希望在开发完成80%任务后立即将代码切换到QA团队。这意味着CountDownLatch允许我们修改可用于等待另一个线程进行部分执行的实现。
上述代码修改
public void run(){
System.out.println("任务分配给"+currentThread().getName());
try {
Thread.sleep(2000);
System.out.println(currentThread().getName()+"第一阶段任务完成");
latch.countDown();
Thread.sleep(2000);
System.out.println(currentThread().getName()+"第二阶段任务完成");
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println("任务已经被"+currentThread().getName()+"执行完毕");
}
}
执行结果:
任务分配给dev1
任务分配给dev2
dev2第一阶段任务完成
dev1第一阶段任务完成
任务分配给qa执行
qa完成该任务
dev1第二阶段任务完成
任务已经被dev1执行完毕
dev2第二阶段任务完成
任务已经被dev2执行完毕
由执行结果可知qa在第二阶段任务执行之前就已经执行,
这种场景下,用join是没法实现的。
总结:调用join方法需要等待thread执行完毕才能继续向下执行,而CountDownLatch只需要检查计数器的值为零就可以继续向下执行,相比之下,CountDownLatch更加灵活一些,可以实现一些更加复杂的业务场景。