开启掘金成长之旅!这是我参与「掘金日新计划 · 12 月更文挑战」的第18天,点击查看活动详情
- countDownLatch这个类使一个线程等待其他线程各自执行完毕后再执行。
- 是通过一个 state(相当于计数器)的东西来实现的,计数器的初始值是 线程的数量或者任务的数量。
- 每当一个线程执行完毕后,计数器的值就-1,当计数器的值为0时,表示所有线程都执行完毕,然后在闭锁上等待的线程就可以恢复工作了。
- CountDownLatch的方便之处在于,你可以在一个线程中使用, 也可以在多个线程上使用,一切只依据状态值,这样便不会受限于任何的场景。
使用场景一
需求
- 可能刚从数据库读取了一批数据
- 利用并发处理这批数据
- 当所有的数据处理完成后,再去执行后面的操作
解决方案
-
第一种:可以利用 join 的方法,但是在线程池中,比较麻烦。
-
第二种:利用线程池的awaitTermination,阻塞一段时间。
- 当使用awaitTermination时,主线程会处于一种等待的状态,等待线程池中所有的线程都运行完毕后才继续运行。
-
第三种:利用CountDownLatch,每当任务完成一个,就计数器减一。
场景一使用如下(每当任务完成一个,就计数器减一):
public static void main(String[] args) throws InterruptedException {
CountDownLatch countDownLatch = new CountDownLatch(6);
for (int i = 0; i < 6; i++) {
new Thread(() ->{
System.out.println("\t\t" + Thread.currentThread().getName() + "处理完毕~~~");
countDownLatch.countDown();
System.out.println("非调用者线程-" + Thread.currentThread().getName() + "-还可以干点其他事");
}, Country.forEach_Country(i + 1).getCountryName()).start();
}
countDownLatch.await();
System.out.println("-----------------------------");
System.out.println("\t 所有任务都已经处理完毕,可以往后执行了!");
}
}
场景二: 因为countdown只会阻塞调用者,其它线程干完任务就可以干其他事。这里的调用者线程就是main线程。
- 多个线程协同工作
- 多个线程需要等待其他线程的工作之后,再进行其后续工作。
- 被唤醒后继续执行其他操作
public static void main(String[] args) throws InterruptedException {
final CountDownLatch latch = new CountDownLatch(1);
new Thread(() -> {
System.out.println(Thread.currentThread().getName() + " Do some initial working.");
try {
Thread.sleep(1000);
latch.await();
System.out.println(Thread.currentThread().getName() + " Do other working.");
} catch (InterruptedException e) {
e.printStackTrace();
}
}).start();
new Thread(() -> {
System.out.println(Thread.currentThread().getName() + " Do some initial working.");
try {
Thread.sleep(1000);
latch.await();
System.out.println(Thread.currentThread().getName() + " Do other working.");
} catch (InterruptedException e) {
e.printStackTrace();
}
}).start();
new Thread(() -> {
System.out.println("asyn prepare for some data.");
try {
Thread.sleep(2000);
System.out.println("Data prepare for done.");
} catch (InterruptedException e) {
e.printStackTrace();
}finally {
latch.countDown();
}
}).start();
}
常用API
构造方法只有一个
CountDownLatch(int count):构造一个以给定计数
实例方法
-
public void await()- 当前线程等到锁存器计数到零
- 可以被 打断
-
public boolean await(long timeout,TimeUnit unit)- 等待一段时间
- timeout - 等待的最长时间 , unit - timeout参数的时间单位
- 如果 指定的等待时间过去,则返回值false
- 如果 计数达到零,则方法返回值为true
-
public void countDown()- 减少锁存器的计数, 如果计数达到零,释放所有等待的线程。
-
public long getCount()- 返回当前计数