CountDownLatch是(算)什么东西?


前言

CountDownLatch字面意思是倒计时门闩,是基于AQS共享锁实现的,主要有两个方法,countDown方法和await方法。创建CountDownLatch时会指定count数量,count不为0时调用await方法线程会阻塞,每调用一次countDown方法会将count减1,直到count==0时await方法才会解除阻塞。

使用方式

先来看看使用方法,主要有以下两种:
第一种:
主线程等待子线程执行完任务再往下执行,伪代码如下

class Driver2 { // ...
   	public static void main(String[] args) {
    	CountDownLatch doneSignal = new CountDownLatch(N);
    	Executor e = Executors.newFixedThreadPool(10);
	    for (int i = 0; i < N; ++i) // create and start threads
	       	e.execute(new WorkerRunnable(doneSignal, i));
	     	doneSignal.await();           // wait for all to finish
   		}
 	}
}
class WorkerRunnable implements Runnable {
	private final CountDownLatch doneSignal;
   	private final int i;
   	WorkerRunnable(CountDownLatch doneSignal, int i) {
     	this.doneSignal = doneSignal;
    	this.i = i;
  	}
   	public void run() {
     	try {
	      doWork(i);
	      doneSignal.countDown();
     	} catch (InterruptedException ex) {} // return;
  	}

   	void doWork() { ... }
}

第二种:
多个子线程等待主线程的发号施令,主线程等待子线程完成后往下执行,伪代码如下:

class Driver {
   	public static void main(String[] args) {
	    CountDownLatch startSignal = new CountDownLatch(1);
	    CountDownLatch doneSignal = new CountDownLatch(N);

    	for (int i = 0; i < N; ++i) // create and start threads
       		new Thread(new Worker(startSignal, doneSignal)).start();

     	doSomethingElse();            // don't let run yet
   		startSignal.countDown();      // let all threads proceed
    	doSomethingElse();
    	doneSignal.await();           // wait for all to finish
 	}
}
class Worker implements Runnable {
   	private final CountDownLatch startSignal;
   	private final CountDownLatch doneSignal;
  	Worker(CountDownLatch startSignal, CountDownLatch doneSignal) {
	    this.startSignal = startSignal;
	    this.doneSignal = doneSignal;
  	}
   	public void run() {
		try {
		      startSignal.await();
		      doWork();
		      doneSignal.countDown();
	     } catch (InterruptedException ex) {} // return;
   	}
  	void doWork() { ... }
}

二、源码解析

1.内部类Sync

既然是基于AQS实现,那么就必须继承AQS,实现对应的方法,然后再确定AQS中的state属性在该实现类中代表什么含义。在CountDownLatch中,state代表的含义就是count。

// 先看看构造方法
public CountDownLatch(int count) {
    if (count < 0) throw new IllegalArgumentException("count < 0");
    this.sync = new Sync(count);
}

private static final class Sync extends AbstractQueuedSynchronizer {
    Sync(int count) {
        setState(count); // state即为count
    }

    int getCount() {
        return getState();
    }
	// 获取锁,count为0获取锁成功,不为0获取锁失败
    protected int tryAcquireShared(int acquires) {
        return (getState() == 0) ? 1 : -1;
    }
	// 释放锁,调用一次count减1,如果count==0返回释放成功,否则失败
    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;
        }
    }
}

主要方法

countDown()

AQS方法,释放锁。会调用上面实现的tryReleaseShared,如果该方法返回true,则会唤醒因获取该锁而阻塞的线程,并且可以往后传播。
将count减1,如果count==0则唤醒所有await等待线程,因为是共享锁,可以传播。

public void countDown() {
 	sync.releaseShared(1);
}

await()

AQS方法,获取锁,获取失败则阻塞。会调用上面实现的tryAcquireShared至少一次。

public void await() throws InterruptedException {
    sync.acquireSharedInterruptibly(1);
}

总结

基于AQS实现的CountDownLatch是非常简单的,在此也不得不感叹AQS同步框架的厉害之处和所处的核心地位。还是那句话,想要基于AQS实现同步器,只要明确了state属性的含义,再实现对应的方法就可以了。阅读基于AQS实现的同步器我们只需要找准state的含义和阅读对应方法的实现就能明白这个同步器实现原理了。AQS懂了同步器这一块基本上就没啥问题了。
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值