并发编程 —— CountDownLatch
CountDownLatch,是我在平时开发过程中,比较常用到的线程辅助类。
常见的应用场景:主线程需等于其它线程任务完成后,才可继续执行。
举个例子,我想看在播放器上看下载到本地的电影。那么下载播放器和下载电影,就是两个任务。下载播放器的同时,也可以下载电影。可以并发处理。而我的主线程,需要等待这两个任务完成后,才可继续继续进行。像这种场景,我们就可以使用CountDownLatch来进行管理。
api介绍
//参数count为计数值
public CountDownLatch(int count){};
//调用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(){};
初始化,给定count值。然后开多线程去执行任务,任务执行完毕后,调用countDown函数对count值进行减1。等到count值为0时,await函数便继续执行。
例子
public class CountDownLatchDemo {
public static void main(String[] args) {
ExecutorService es = Executors.newFixedThreadPool(2);
final CountDownLatch latch = new CountDownLatch(2);
es.submit(() -> {
//do something...
foo();
latch.countDown();
});
es.submit(() -> {
//do something...
bar();
latch.countDown();
});
try {
//
latch.await();
System.out.println("done");
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
}
/**
* test method 1.
*/
private static void foo(){
try {
Thread.sleep(3000);
System.out.println("i am foo");
} catch (InterruptedException foo) {
foo.printStackTrace();
}
}
/**
* test method 2.
*/
private static void bar(){
try {
Thread.sleep(100);
System.out.println("i am bar");
} catch (InterruptedException foo) {
foo.printStackTrace();
}
}
}
console:
i am bar
i am foo
done
修改其中一行代码:
latch.await(2000, TimeUnit.MILLISECONDS);
console:
i am bar
done
i am foo
规范一点儿的写法呢,建议用下面这个形式,try catch所要执行的操作,在finally块再countDown
es.submit(() -> {
//do something...
try {
foo();
}catch (Exception var1){
//do nothing
}finally {
latch.countDown();
}
});
es.submit(() -> {
//do something...
try{
bar();
}catch (Exception var2){
//do nothing
}finally {
latch.countDown();
}
});