Java并发编程
CountDownLatch的使用
允许一个或多个线程等待直到在其他线程中执行的一组操作完成的同步辅助。
简述
CountDownLatch
用给定的计数初始化。 await
方法阻塞,直到由于countDown()
方法的调用而导致当前计数达到零,之后所有等待线程被释放,并且任何后续的await
调用立即返回。 这是一个一次性的现象 - 计数无法重置。 如果需要重置计数的版本,请考虑使用CyclicBarrier
。
CountDownLatch
是一种通用的同步工具,可用于多种用途。 一个CountDownLatch
为一个计数的CountDownLatch用作一个简单的开/关锁存器,或者门:所有线程调用await
在门口等待,直到被调用countDown()
的线程打开。 一个CountDownLatch
初始化N可以用来做一个线程等待,直到N个线程完成某项操作,或某些动作已经完成N次。
CountDownLatch
一个有用的属性是,它不要求调用countDown
线程等待计数到达零之前继续,它只是阻止任何线程通过await
,直到所有线程可以通过。
也就是相当于一个高铁检票口,需要在时间倒数到检票时间的时候,才会放行,不然,都得在候车厅等待。此时高铁就如同需要执行的下一个任务,乘客就相当于阻塞的线程。
API
其实对于这个类而言,涉及到的方法不多,只有下面的几个,所以运用也不是很难。
Modifier and Type | Method and Description |
---|---|
void | await() 导致当前线程等到锁存器计数到零,除非线程是 interrupted 。 |
boolean | await(long timeout, TimeUnit unit) 使当前线程等待直到锁存器计数到零为止,除非线程为 interrupted或指定的等待时间过去。 |
void | countDown() 减少锁存器的计数,如果计数达到零,释放所有等待的线程。 |
long | getCount() 返回当前计数。 |
String | toString() 返回一个标识此锁存器的字符串及其状态。 |
示例程序
package CountDownLatchLearn;
import java.util.concurrent.CountDownLatch;
public class Latch {
static class MyService {
private CountDownLatch latch = new CountDownLatch(3);
public void testMethod() {
try {
if (Thread.currentThread().getName().equals("线程4")) {
Thread.sleep(3000);
}
System.out.println(Thread.currentThread().getName() + "准备");
latch.await();
System.out.println(Thread.currentThread().getName() + "结束");
} catch (InterruptedException e) {
System.out.println("Exception:" + e);
e.printStackTrace();
}
}
public void downMethod() {
latch.countDown();
}
}
static class MyThread extends Thread {
private MyService myService;
public MyThread(MyService myService) {
super();
this.myService = myService;
}
@Override
public void run() {
myService.testMethod();
}
}
public static void main(String[] args) throws InterruptedException {
MyService service = new MyService();
MyThread[] threads = new MyThread[10];
for (int i = 0; i < threads.length; i++) {
threads[i] = new MyThread(service);
threads[i].setName("线程" + (i + 1));
threads[i].start();
}
System.out.println("预备");
for (int i = 3; i >= 1; i--) {
System.out.println(i);
Thread.sleep(1000);
service.downMethod();
}
System.out.println("====START====");
}
}
在这个简单的程序中,设计的是一个起跑发令,主线程main用于放行所有准备好的线程,其中我专门设计一个线程的准备时间超过了main的最长等待时间,我们可以通过运行结果看出一点问题:
预备
3
线程3准备
线程10准备
线程1准备
线程9准备
线程2准备
线程6准备
线程7准备
线程8准备
线程5准备
2
1
====START====
线程10结束
线程6结束
线程1结束
线程9结束
线程3结束
线程7结束
线程4准备 =====> 别人都起跑了,才准备好
线程2结束
线程5结束
线程8结束
线程4结束
Process finished with exit code 0