倒计时器CountDownLatch
CountDownLatch
是JDK 5+里面闭锁的一个实现,允许一个或者多个线程等待某个事件的发生。今天我们通过一些实例来学习一下它的用法。
CountDownLatch的使用
CountDownLatch
被用来同步一个或多个线程,强制它们等待由其他线程执行的一组操作完成。你可以向CountDownLatch
对象设置一个初始计数值,任何在这个对象上调用await()
方法都将阻塞,直至这个计数值达到0
。其他线程在结束工作时,可以在该对象上调用countDown()
方法来减小这个计数值。
CountDownLatch
被设计为只触发一次,计数值不能被重置。如果你需要能够重置计数值的版本,则可以使用CyclicBarrier。
只有等线程1、线程2和线程3中都运行结束后,才可以运行线程4。即一定数量的线程都完成工作后,才可以共同触发后续的一个或多个线程的开始工作。
CountDownLatch
的构建函数接收一个整数为参数,即当前这个计数器的计数个数。
public CountDownLatch(int count) {
if (count < 0) throw new IllegalArgumentException("count < 0");
this.sync = new Sync(count);
}
其中的count
其实就是: 线程可以通过等待之前必须调用countDown
的次数。
CountDownLatch
中的方法:
public void await() throws InterruptedException
public boolean await(long timeout, TimeUnit unit) throws InterruptedException
public void countDown()
public long getCount()
await
: 导致当前线程等待,直到锁存器倒数为零或者线程被中断。带有参数的await
方法多一种方式结束等待:指定的等待时间已过countDown
: 递减锁存器的计数,如果计数达到零,则释放所有等待线程getCount
: 返回当前计数,一般用于调度或者测试
下面我们给出一个例子:阻止任何工人开始工作,直到司机准备好
public class CountDownLatchTest {
final static CountDownLatch startSignal = new CountDownLatch(1);
final static CountDownLatch doneSignal = new CountDownLatch(5);
public static void main(String[] args) throws Exception {
for (int i = 0; i < 5; ++i)
new Thread(new TaskWorker()).start();
startSignal.countDown();
System.out.println("Diver is ready, workers can start to work: " + LocalDateTime.now());
TimeUnit.SECONDS.sleep(1);
System.out.println("Diver is waiting for the workers done their works " + LocalDateTime.now());
doneSignal.await();
System.out.println("Workers has done their works, Diver start the car. " + LocalDateTime.now());
}
private static class TaskWorker implements Runnable {
@Override
public void run() {
try {
startSignal.await();
System.out.println("Worker: " + Thread.currentThread().getName() + " done the work, time: " + LocalDateTime.now());
doneSignal.countDown();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
输出结果为:
Diver is ready, workers can start to work: 2023-08-15T20:40:59.137129
Worker: Thread-0 done the work, time: 2023-08-15T20:40:59.137085
Worker: Thread-1 done the work, time: 2023-08-15T20:40:59.137092
Worker: Thread-3 done the work, time: 2023-08-15T20:40:59.137106
Worker: Thread-2 done the work, time: 2023-08-15T20:40:59.137088
Worker: Thread-4 done the work, time: 2023-08-15T20:40:59.137113
Diver is waiting for the workers done their works 2023-08-15T20:41:00.144588
Workers has done their works, Diver starts the car. 2023-08-15T20:41:00.145089
这里我们创建两个CountDownLatch
:
startSignal
的计数量为1,可以当成是启动信号,阻止任何工人开始工作,直到驾驶员准备好让他们继续操作doneSignal
的计数量为5,可以当成是完成信号,让驾驶员等待直到所有工作人员完成任务
代码里面我们创建五个线程TaskWorker
模拟五个工人,他们需要一直等待startSignal.await()
直到驾驶员发送开始的信号。在main
线程中startSignal.countDown()
表示驾驶员发送了开始的信号。于是五个工人开始了工作(done the work...
),于此同时驾驶员在等待所有工人完成工作doneSignal.await()
。
工人完成自己的工作时,会告知驾驶员自己工作已完成的信号doneSignal.countDown()
。当驾驶员收到所有工人完成工作的信号后,便开始启动了车辆扬长而去(Diver start the car
)....