CountDownLatch也叫闭锁,在JDK1.5被引入,CountDownLatch是一个同步工具类,它允许一个或多个线程一直等待,直到其他线程的操作执行完后再执行。
使用示例
CountDownLatch的构造函数接收一个int类型的参数作为计数器,如果你想等待***N个点***完成,这里就传入N。当调用CountDownLatch的countDown方法时,N就会减1,CountDownLatch的await方法会阻塞当前线程,直到N变成零。
N个点:由于CountDownLatch方法可以用在任何地方,这里说的N个点,可以是N个线程,也可以是1个线程里的N个执行步骤。用在多个线程时,只需要把CountDownLatch的引用传递到线程里即可。
public class CountDownLatchDemo {
final static SimpleDateFormat sdf=new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
public static void main(String[] args) throws InterruptedException {
CountDownLatch latch=new CountDownLatch(2);//两个工人的协作
Worker worker1=new Worker("zhang san", 5000, latch);
Worker worker2=new Worker("li si", 8000, latch);
worker1.start();//
worker2.start();//
latch.await();//等待所有工人完成工作
System.out.println("all work done at "+sdf.format(new Date()));
}
static class Worker extends Thread{
String workerName;
int workTime;
CountDownLatch latch;
public Worker(String workerName ,int workTime ,CountDownLatch latch){
this.workerName=workerName;
this.workTime=workTime;
this.latch=latch;
}
public void run(){
System.out.println("Worker "+workerName
+" do work begin at "+sdf.format(new Date()));
doWork();//工作了
System.out.println("Worker "+workerName
+" do work complete at "+sdf.format(new Date()));
latch.countDown();//工人完成工作,计数器减一
}
private void doWork(){
try {
Thread.sleep(workTime);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
实现原理
CountDownLatch内部会维护一个初始值为线程数量的计数器,主线程执行await方法,如果计数器大于0,则阻塞等待。当一个线程完成任务后,计数器值减1。当计数器为0时,表示所有的线程已经完成任务,等待的主线程被唤醒继续执行。CountDownLatch实现主要基于java同步器AQS,其内部维护一个AQS子类,并重写了相关方法。
private static final class Sync extends AbstractQueuedSynchronizer {
Sync(int count) {
setState(count);
}
int getCount() {
return getState();
}
protected int tryAcquireShared(int acquires) {
return (getState() == 0) ? 1 : -1;
}
protected boolean tryReleaseShared(int releases) {
// Decrement count; signal when transition to zero
for (;;) {
int c = getState();
if (c == 0)
return false;
int nextc = c-1;
if (compareAndSetState(c, nextc))
return nextc == 0;
}
}
}
await方法源码如下:
public void await() throws InterruptedException {
sync.acquireSharedInterruptibly(1);
}
await方法执行过程流程图如下:
countDown方法源如下:
public void countDown() {
sync.releaseShared(1);
}
countDown方法执行过程和await方法相似,不具体分析。
注意事项
- CountDownLatch不可能重新初始化或者修改CountDownLatch对象的内部计数器的值。
欢迎留言补充,共同交流。个人微信公众号求关注: