CountDownLatch是一个同步工具,它允许一个或者多个线程一直等待,直到其他线程的操作执行完成后在执行。
CountDownLatch是通过一个计数器来实现的,计数器的初始值为线程的数量。每当一个线程完成了自己的任务后,计数器的值就会减1。当计数器的值达到0时,它表示所有的线程已经完成了任务,然后在闭锁上等待的线程就可以恢复执行任务。
1. 源码分析: 源码位于rt.java 中的java.util.concurrent包中。
中文解释: 主线程在等待所有其他的子线程执行完成后在往下执行
2、构造函数:CountDownLatch(int count)//初始化count数目的同步计数器,只有当同步计数器为0,主线程才会向下执行
主要方法:void await()//当前线程等待计数器为0
boolean await(long timeout, TimeUnit unit)//与上面的方法不同,它加了一个时间限制。
void countDown()//计数器减1
long getCount()//获取计数器的值
3、它的内部有一个辅助的内部类: sync
实现如下:
/**
* Synchronization control For CountDownLatch.
* Uses AQS state to represent count.
*/
private static final class Sync extends AbstractQueuedSynchronizer {
private static final long serialVersionUID = 4982264981922014374L;
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;
}
}
}
4.await()方法的实现
public void await() throws InterruptedException {
sync.acquireSharedInterruptibly(1);
}
public final void acquireSharedInterruptibly(int arg)
throws InterruptedException {
if (Thread.interrupted())
throw new InterruptedException();
//调用3中的tryAcquireShared()方法
if (tryAcquireShared(arg) < 0)
doAcquireSharedInterruptibly(arg);//加入到等待队列中
}
5.countDown()方法的实现
public void countDown() {
sync.releaseShared(1);
}
public final boolean releaseShared(int arg) {
//调用3中的tryReleaseShared()方法
if (tryReleaseShared(arg)) {
//解锁
doReleaseShared();
return true;
}
return false;
}
应用场景:
比如主任务是一个比较复杂的运算,为了节约时间,我们可以拆分为多个子任务,多线程同时执行,最终统一汇总任务。
其实生活也有类似的场景,比如马拉松赛跑,我们不可能按顺序依次跑步,这样得跑到猴年马月。一般来说都是大家听到发号命令一起跑,最终比赛结束,统一汇总成绩。
代码案列:
下面看一个例子大家就清楚CountDownLatch的用法了:
/**
* CountDownLatch,一个同步辅助类,在完成一组正在其他线程中执行的操作之前,它允许一个或多个线程一直等待
* 构造方法参数指定了计数的次数
* countDown方法,当前线程结束执行后调用,计数减一
* awaint方法,调用此方法会一直阻塞当前线程,直到计时器的值为0
* 创建时间 2017年8月15日
*
*/
public class CountDownLatchDemo {
final static SimpleDateFormat sdf = new SimpleDateFormat(
"yyyy-MM-dd HH:mm:ss");
final static String startTime = sdf.format(new Date());
public static void main(String[] args) throws InterruptedException {
CountDownLatch latch = new CountDownLatch(2);// 两个赛跑者
Runer runer1 = new Runer("刘翔", 5000, latch);
Runer runer2 = new Runer("罗伯斯", 8000, latch);
runer1.start();//刘翔 开始跑步
runer2.start();//罗伯斯 开始跑步
latch.await();// 等待所有人赛跑结束
System.out.println("all runer done at " + sdf.format(new Date()));
}
static class Runer extends Thread {
String runerName;
int runTime;
CountDownLatch latch;
public Runer(String runerName, int runTime, CountDownLatch latch) {
this.runerName = runerName;
this.runTime = runTime;
this.latch = latch;
}
public void run() {
System.out.println("Runer " + runerName + " do run begin at "
+ startTime);
doRun();//跑步
System.out.println("Runer " + runerName + " do run complete at "
+ sdf.format(new Date()));
latch.countDown();// 终点结束,计数器减一
}
private void doRun() {
try {
Thread.sleep(runTime);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}