CountDownLatch的理解使用
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
CountDownLatch的理解使⽤
⼀、介绍
CountDownLatch是jdk1.5中引⼊的⼀种同步辅助,允许⼀个或者多个线程等待,知道在其他线程中执⾏的⼀组操作完成。
CountDownLatch使⽤给定的计数器进⾏初始化,由于调⽤了countDown⽅法,await⽅法会阻塞,知道当前计数器达到为零,然后释放所有等待线程,并且任何后续的await⽅法都会⽴即返回,由于在初始化时指定了计数数量,所以⽆法重置技术,如果需要重置计数,需要使⽤CyclicBarrier.
计数为1的CountDownLatch可⽤于简单的锁,调⽤await的所有线程在等待,直到它被调⽤countDown的线程打开,初始化为N的线程可⽤于使⼀个主线程等待,直到N个线程完成操作执⾏完成,或者某个操作已完成N次。
使⽤场景最多的可能是主线程等待所有⼦线程是否执⾏完毕。
简单来说,CountDownLatch类是⼀个基于AbstractQueuedSynchronizer(AQS)实现的计数器,可以设置初始化线程数(设置完后不可改变),在⼦线程结束时调⽤countDown()⽅法可以使计数数量减1,当所有线程结束,即最终getCount()为0时,会调⽤CountDownLatch的成员⽅法wait()的线程就会取消BLOCKED阻塞状态,进去RUNNABLE从⽽继续执⾏。
⼆、使⽤
下⾯来看源码⾥举的例⼦,我理解的是四个搬运⼯装车
import java.util.concurrent.CountDownLatch;
/**
* 司机
* @author
*/
public class Driver {
public static void main(String[] args) throws InterruptedException {
int N = 4;
// 开始装车信号
CountDownLatch startSignal = new CountDownLatch(1);
// 装车完毕信号
CountDownLatch doneSignal = new CountDownLatch(N);
// 初始化四个搬运⼯
for (int i = 0; i < N; ++i) {
new Thread(new WorkerRunnable(startSignal, doneSignal), "Worker-" + i).start();
}
// 司机做准备⼯作,⽐如把车开到指定地⽅
doSomethingElse();
// 准备完了,发信号让开始搬运
startSignal.countDown();
// 司机等待所有搬运⼯完成
doneSignal.await();
// 完成
doSomethingElse2();
}
static void doSomethingElse() throws InterruptedException {
Thread.sleep(1000);
System.out.println("司机准备⼯作完成");
}
static void doSomethingElse2() throws InterruptedException {
Thread.sleep(1000);
System.out.println("滴,滴滴~ ⽼司机发车了");
}
}
import java.util.Random;
import java.util.concurrent.CountDownLatch;
/**
* 搬运⼯
* @author 15641
*/
public class WorkerRunnable implements Runnable{
private final CountDownLatch startSignal;
private final CountDownLatch doneSignal;
public WorkerRunnable(CountDownLatch startSignal, CountDownLatch doneSignal) {
this.startSignal = startSignal;
this.doneSignal = doneSignal;
}
@Override
public void run() {
try {
// 搬运⼯等待准备⼯作完成
startSignal.await();
// 开始⼯作
doWork();
// 装完之后给司机发个信号
doneSignal.countDown();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
void doWork() throws InterruptedException {
// 模拟每个⼯⼈的装车速度
Random random = new Random();
Thread.sleep((long)(random.nextDouble() * 5000));
System.out.println(Thread.currentThread().getName() + "装完了");
}
}
执⾏结果为
上述例⼦是多个主线程等待多个线程全部执⾏完,第⼆个例⼦是使⽤线程池⽤⼀个Runnable重复执⾏每⼀部分import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
/**
* @author 15641
*/
public class Driver2 {
public static void main(String[] args) throws InterruptedException {
int N = 4;
CountDownLatch doneSignal = new CountDownLatch(N);
ExecutorService service = Executors.newFixedThreadPool(N);
for (int i = 0; i < N; ++i) {
service.submit(new WorkerRunnable2(doneSignal, i));
}
doneSignal.await();
}
}
import java.util.Random;
import java.util.concurrent.CountDownLatch;
/**
* @author 15641
*/
public class WorkerRunnable2 implements Runnable{
private final CountDownLatch doneSingal;
private final int i;
public WorkerRunnable2(CountDownLatch doneSingal, int i) {
this.doneSingal = doneSingal;
this.i = i;
}
@Override
public void run() {
try {
doWork(i);
doneSingal.countDown();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
void doWork(int i) throws InterruptedException {
// 模拟每个⼯⼈的装车速度
Random random = new Random();
Thread.sleep((long)(random.nextDouble() * 8000)); System.out.println("任务" + i + "完成了");
}
}。