CountDownLatch介绍
CountDownLatch是一个同步工具类,它允许一个或多个线程一直等待,直到其他线程执行完后再执行。
CountDownLatch是在java1.5被引入的,跟它一起被引入的并发工具类还有CyclicBarrier、Semaphore、ConcurrentHashMap和BlockingQueue,它们都存在于java.util.concurrent包下
CountDownLatch原理
CountDownLatch是通过一个计数器来实现的,计数器的初始化值为线程的数量。每当一个线程完成了自己的任务后,计数器的值就相应得减1。当计数器到达0时,表示所有的线程都已完成任务,然后在闭锁上等待的线程就可以恢复执行任务。
/**
* 串行的步骤,中间有些步骤可以并行处理,提高效率。就可以使用CountDownLatch
*/
public class CountDownLatchExample {
private static Random random = new Random(System.currentTimeMillis());
private static ExecutorService executor = Executors.newFixedThreadPool(2);
private final static CountDownLatch latch = new CountDownLatch(10);
public static void main(String[] args) throws InterruptedException{
//1.
int[] data = query();
//2.
for(int i=0;i<data.length;i++){
executor.execute(new SimpleRunnable(data,i,latch));
}
//3.
latch.await();
System.out.println("all of work finish done");
executor.shutdown();
// executor.awaitTermination(1, TimeUnit.HOURS);
}
static class SimpleRunnable implements Runnable{
private final int[] data;
private final int index;
private final CountDownLatch latch;
public SimpleRunnable(int[] data,int index, CountDownLatch latch) {
this.data = data;
this.index = index;
this.latch = latch;
}
@Override
public void run() {
try {
Thread.sleep(random.nextInt(2000));
} catch (InterruptedException e) {
e.printStackTrace();
}
int value = data[index];
if (value%2==0) {
data[index] = value*2;
} else{
data[index] = value *10;
}
System.out.println(Thread.currentThread().getName()+" finish");
latch.countDown();
System.out.println(latch.getCount());
}
}
private static int[] query(){
return new int[]{1,2,3,4,5,6,7,8,9,10};
}
}
源码解析
构造CountDownLatch传入的计数器实际为Sync中state的值
public CountDownLatch(int count) {
if (count < 0) throw new IllegalArgumentException("count < 0");
// count实际为同步器中state
this.sync = new Sync(count);
}
CountDownLatch内部类Sync继承自AbstractQueuedSynchronizer
Sync(int count) {
setState(count);
}
await方法调用链
CountDownLatch#await方法
public void await() throws InterruptedException {
sync.acquireSharedInterruptibly(1);
}
AbstractQueuedSynchronizer#acquireSharedInterruptibly方法
public final void acquireSharedInterruptibly(int arg)
throws InterruptedException {
if (Thread.interrupted())
throw new InterruptedException();
if (tryAcquireShared(arg) < 0)
doAcquireSharedInterruptibly(arg);
}
CountDownLatch#Sync#tryAcquireShared方法
protected int tryAcquireShared(int acquires) {
//当计数器=0的时候,返回1
return (getState() == 0) ? 1 : -1;
}
AbstractQueuedSynchronizer#doAcquireSharedInterruptibly方法
private void doAcquireSharedInterruptibly(int arg)
throws InterruptedException {
// 将当前线程构造的节点加入同步队列队尾
final Node node = addWaiter(Node.SHARED);
boolean failed = true;
try {
for (;;) {
// 获取当前节点的前驱
final Node p = node.predecessor();
if (p == head) {
int r = tryAcquireShared(arg);
if (r >= 0) {
// 获取锁成功
setHeadAndPropagate(node, r);
p.next = null; // help GC
failed = false;
return;
}
}
if (shouldParkAfterFailedAcquire(p, node) &&
parkAndCheckInterrupt())
throw new InterruptedException();
}
} finally {
if (failed)
cancelAcquire(node);
}
}
上面的例子在main方法中,调用latch.await();,由于刚开始构造的时候,state=10,不等0.条件tryAcquireShared(arg) < 0成立,进入doAcquireSharedInterruptibly方法,由于此方法中退出的唯一条件为r >= 0即state=0,使得main线程在该方法中循环,直到cpu调度,其余10个线程都执行countDown方法,使得state变为0,才能退出循环,从而退出await方法
countDown方法调用链
CountDownLatch#countDown方法
public void countDown() {
// 如果state!=0,直接返回
sync.releaseShared(1);
}
AbstractQueuedSynchronizer#releaseShared方法
public final boolean releaseShared(int arg) {
if (tryReleaseShared(arg)) {
doReleaseShared();
return true;
}
return false;
}
CountDownLatch#Sync#tryReleaseShared方法
protected boolean tryReleaseShared(int releases) {
// Decrement count; signal when transition to zero
for (;;) {
// 获取计数器的值
int c = getState();
if (c == 0)
return false;
// 计数器-1
int nextc = c-1;
//更新state的值
if (compareAndSetState(c, nextc))
//state值为0,返回true
return nextc == 0;
}
}
上面的例子latch.countDown();除非state=0,否则直接返回,往下执行