课外作业之CountDownLatch应用详解
CountDownLatch应用详解
姓名:李纯
学号:150341312
1)概述
CountDownLatch是一个同步辅助类,在完成一组正在其他线程中执行的操作之前,它允许一个或多个线程一直等待。
CountDownLatch的一个非常典型的应用场景是:有一个任务想要往下执行,但必须要等到其他的任务执行完毕后才可以继续往下执行。假如我们这个想要继续往下执行的任务调用一个CountDownLatch对象的await()方法,其他的任务执行完自己的任务后调用同一个CountDownLatch对象上的countDown()方法,这个调用await()方法的任务将一直阻塞等待,直到这个CountDownLatch对象的计数值减到0为止。
主要方法:
public CountDownLatch(int count);
构造一个用给定计数初始化的 CountDownLatch。
参数:
count - 在线程能通过 await() 之前,必须调用countDown() 的次数。
抛出:
IllegalArgumentException - 如果 count 小于零。
public void countDown();
递减锁存器的计数,如果计数到达零,则释放所有等待的线程。
如果当前计数大于零,则将计数减少 1。
如果新的计数为零,出于线程调度目的,将重新启用所有的等待线程。
如果当前计数等于零,则不发生任何操作。
public void await(long timeout,TimeUnitunit) throws InterruptedException
使当前线程在锁存器倒计数至零之前一直等待,除非线程被中断或超出了指定的等待时间。
如果当前计数为零,则此方法立刻返回 true 值。
如果当前计数大于零,则出于线程调度目的,将禁用当前线程,且在发生以下三种情况之一前,该线程将一直处于休眠状态:
· 由于调用 countDown() 方法,计数到达零;或者
· 其他某个线程中断当前线程;或者
· 已超出指定的等待时间。
如果计数到达零,则该方法返回 true 值。
如果当前线程:
· 在进入此方法时已经设置了该线程的中断状态;或者
· 在等待时被中断,
则抛出 InterruptedException,并且清除当前线程的已中断状态。如果超出了指定的等待时间,则返回值为 false。如果该时间小于或等于零,则此方法根本不会等待。
参数:
timeout - 要等待的最长时间
unit - timeout 参数的时间单位。
返回:
如果计数到达零,则返回 true;如果在计数到达零之前超过了等待时间,则返回 false。
抛出:
InterruptedException - 如果当前线程在等待时被中断。
2)应用示例:
示例1:
将两位工人协作工作的开始时间和结束时间显示在屏幕上
package lichun;
import java.sql.Date;
import java.text.SimpleDateFormat;
import java.util.concurrent.CountDownLatch;
public class CoutDownLatchDemo {
final static SimpleDateFormatsdf=new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
@SuppressWarnings("deprecation")
public static void main(String[]args)throws InterruptedException {
CountDownLatch latch=new CountDownLatch(2);//两个工人的协作
Worker worker1=new Worker("zhang san", 5000,latch);
Worker worker2=new Worker("li chun", 8000,latch);
worker1.start();//
worker2.start();// c
latch.await();//等待所有工人完成工作
System.out.println("all work done at "+sdf.format(new Date(2017,
11, 14)));
}
static class Workerextends Thread{
String workerName;
int workTime;
CountDownLatch latch;
public Worker(StringworkerName ,int workTime ,CountDownLatchlatch){
this.workerName=workerName;
this.workTime=workTime;
this.latch=latch;
}
public void run(){
System.out.println("Worker "+workerName+"
do work begin at "+sdf.format(new Date(2017, 11, 1)));
doWork();//工作了
System.out.println("Worker "+workerName+"
do work complete at "+sdf.format(new Date(2017, 11, 14)));
latch.countDown();//工人完成工作,计数器减一
}
private void doWork(){
try {
Thread.sleep(workTime);
} catch (InterruptedExceptione) {
e.printStackTrace();
}
}
}
}
输出结果:
实现原理:
根据count=2,计数达到零后结束线程,输出工人的工作时间。
示例2:
模拟了100米赛跑,10名选手已经准备就绪,只等裁判一声令下。当所有人都到达终点时,比赛结束。
package lichun;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class CountDownLatchTest {
public static void main(String[]args)throws InterruptedException {
// 开始的倒数锁
final CountDownLatchbegin =new CountDownLatch(1);
// 结束的倒数锁
final CountDownLatchend =new CountDownLatch(10);
// 十名选手
final ExecutorServiceexec = Executors.newFixedThreadPool(10);
for (int index = 0;index < 10; index++) {
final int NO =index + 1;
Runnable run = new Runnable() {
public void run() {
try {
// 如果当前计数为零,则此方法立即返回。
// 等待
begin.await();
Thread.sleep((long) (Math.random() * 10000));
System.out.println("No." +NO +" arrived");
} catch (InterruptedExceptione) {
} finally {
// 每个选手到达终点时,end就减一
end.countDown();
}
}
};
exec.submit(run);
}
System.out.println("Game Start");
// begin减一,开始游戏
begin.countDown();
// 等待end变为0,即所有选手到达终点
end.await();
System.out.println("Game Over");
exec.shutdown();
}
}
输出结果:
实现原理:
开始的倒数锁设为1,当它计数到0时开始输出结果;结束的倒数锁设为10,即等待end计数到0时,输出的十名选手的到达情况也随之结束。
3)总结
通过这次对CountDownLatch概念和应用的探索,我比较理解了这个类,它虽然被定义为辅助类型,但是仍然是一个十分实用的计数计时类。它的原理如图所示:
那它在什么时候使用呢:
1. 实现最大的并行性:有时我们想同时启动多个线程,实现最大程度的并行性。例如,我们想测试一个单例类。如果我们创建一个初始计数为1的CountDownLatch,并让所有线程都在这个锁上等待,那么我们可以很轻松地完成测试。我们只需调用 一次countDown()方法就可以让所有的等待线程同时恢复执行。
2. 开始执行前等待n个线程完成各自任务:例如应用程序启动类要确保在处理用户请求前,所有N个外部系统已经启动和运行了。
3. 死锁检测:一个非常方便的使用场景是,你可以使用n个线程访问共享资源,在每次测试阶段的线程数目是不同的,并尝试产生死锁。
这些收获都来自于在网上查找博客,百度和阅读JAVA_API_CN手册,从而我知道了专业知识不仅仅来源于课堂,课堂之外还有更多丰富的资源等着我们去发现去探索,大学中更重要的是自学,去挖掘课堂外的知识,不再是和高中一样,做一只嗷嗷待哺的窝中小鸟。
4)参考文献
JAVA_API_CN手册
http://blog.****.net/shihuacai/article/details/8856370
http://www.iteye.com/topic/1002652
http://www.importnew.com/15731.html