CountDownLatch 线程开关 AQS 共享锁

一、CountDownLatch 源码分析

     CountDownLatch 内部定义了静态内部类Sync,继承了AbstractQueuedSynchronizer(下称AQS,可以查看另一篇博客 AQS源码解读),通过重写tryAcquireShared(获取共享锁),tryReleaseShared(释放共享锁)实现了简单的共享锁。只有当前state为0时,获取锁成功。初始化state为n,则需要调用n次countDown()方法,线程才会获取锁成功。获取成功后状态不可逆,CountDownLatch只有 await()获取锁,和countDown()使state减1。共享线程数量通过构造器传入,获取失败则进入AQS内置的FIFO队列。

内部的Sync:

private static final class Sync extends AbstractQueuedSynchronizer {
        private static final long serialVersionUID = 4982264981922014374L;

        Sync(int count) {
            setState(count);
        }

        int getCount() {
            return getState();
        }

		// 共享锁 返回 大于0 表示获取到了锁 否则为获取锁失败
        protected int tryAcquireShared(int acquires) {
            return (getState() == 0) ? 1 : -1;
        }

		// 自旋  + CAS将当前state减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;
            }
        }
    }

    CountDownLatch 主要有两个方法 await(),countDown()。调用await方法将会一直阻塞至state ==0;countDown() 将state减1。

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

   public void countDown() {
        sync.releaseShared(1);
    }
二、CountDownLatch实战
 class Driver { 
 
        void main() throws InterruptedException {
            CountDownLatch startSignal = new CountDownLatch(1);
            CountDownLatch doneSignal = new CountDownLatch(N);

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

            doSomethingElse();     
            //  startSignal.countDown() 后子线程开始执行
            startSignal.countDown(); 
            doSomethingElse();
            // 阻塞至子线程全部执行完毕
            doneSignal.await();         
    }
  }
 
    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) {} 
    }
 
   void doWork() { ... }

    这个是伪代码,并不能直接运行,代码出自CountDownLatch 的类注释上上面。 定义了两个线程信号 startSignal ,doneSignal。当主线程调用startSignal.countDown() 子线程开始执行, doneSignal.await()会阻塞主线程至子线程全部执行完毕调用doneSignal#countDown(),然后继续执行。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值