什么是CountDownLatch?
一种同步辅助工具,允许一个或多个线程等待其他线程中正在执行的一组操作
完成。
初始化CountDownLatch时传入一个int类型的参数作为计数器,比如传入N,在当在线程中调用CountDownLatch的await方法时,会阻塞当前线程,当在线程中调用CountDownLatch的countDown方法时,N(计数器)减1,当N变成0时,将会释放所有等待的线程,任何后续的await调用都将立即返回。
注意
1、创建CountDownLatch时,计数器必须大于0,等于0时,调用await方法不会阻塞线程。
2、CountDownLatch不能重新初始化或者修改CountDownLatch对象的内部计数器的值。如果需要使用重置计数器的功能,可以考虑使用CyclicBarrier。
CountDownLatch方法
类型 | 方法 | 描述 |
---|---|---|
void | await() | 使当前线程等待闩锁倒数为零,或者线程被中断 |
boolean | await(long timeout, TimeUnit unit) | 使当前线程等待闩锁倒数为零,或者超时 |
void | countDown() | 减少闩锁的计数,如果计数为零,则释放所有等待的线程 |
long | getCount() | 返回当前计数 |
String | toString() | 返回标识此闩锁的字符串及其状态 |
例子
package com.sy.thread.example;
import java.util.concurrent.CountDownLatch;
/**
* Description: thread
*
* @author songyu
*/
public class CountDwonLatchTest {
/**
* 创建CountDownLatch,计数器设置为2
*/
private static CountDownLatch countDownLatch = new CountDownLatch(2);
public static void main(String[] args) throws InterruptedException {
new Thread(new Runnable() {
@Override
public void run() {
System.out.println("1");
//计数器-1
countDownLatch.countDown();
}
}).start();
new Thread(new Runnable() {
@Override
public void run() {
try {
System.out.println("2");
//等待2秒
Thread.sleep(2000);
//计数器-1,countDownLatch的计数器变为0,阻塞线程继续执行
countDownLatch.countDown();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}).start();
//调用await()阻塞当前线程,直到countDownLatch的计数器变为0
countDownLatch.await();
System.out.println("3");
}
}
结果
1
2
3
代码
1.先创建一个CountDownLatch,设置计数器为2
。
2.创建两个线程,调用await()
方法阻塞当前线程。
3.第一个线程执行输出“1”,然后执行countDown()
方法,计数器-1
。
4.第二个线程执行输出“2”,等待2秒,执行countDown()
方法,计数器-1
。
5.当两秒后第二个线程执行完countDown()
方法后,CountDownLatch的计数器变为0
,阻塞线程将继续执行,输出“3”。
使用场景
假设两个线程,A程执行了部分逻辑后需要调用B线程,当B线程处理完后,A线程继续执行,使用CountDownLatch应该怎么实现呢?
package com.sy.thread.example;
import java.util.concurrent.CountDownLatch;
/**
* Description: thread
*
* @author songyu
*/
public class CountDwonLatchTest2 {
/**
* 创建CountDownLatch,计数器设置为2
*/
private static CountDownLatch countDownLatch = new CountDownLatch(1);
static Thread A = new Thread(new Runnable() {
@Override
public void run() {
try {
System.out.println("A线程开始执行");
System.out.println("A线程处理部分逻辑。。。。。。");
System.out.println("让B线程开始执行");
B.start();
countDownLatch.await();
System.out.println("B线程执行结束,A线程继续执行");
System.out.println("执行结束");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
},"A");
static Thread B = new Thread(new Runnable() {
@Override
public void run() {
System.out.println("B线程开始执行");
System.out.println("B线程执行结束,让A线程继续执行");
countDownLatch.countDown();
}
},"B");
public static void main(String[] args) {
A.start();
}
}
执行结果
A线程开始执行
A线程处理部分逻辑。。。。。。
让B线程开始执行
B线程开始执行
B线程执行结束,让A线程继续执行
B线程执行结束,A线程继续执行
执行结束
通过执行结果可以看出在A线程中让B线程开始执行后,调用await()方法进入阻塞,直到B线程执行结束后,调用countDown()方法后,让计数器变为0后,A线程才继续执行。