CountDownLatch是Java并发包下提供的倒计时锁,先看一下CountDownLatch的类图。
![2f57b3339040bfc93e729bd057c5b21b.png](https://i-blog.csdnimg.cn/blog_migrate/a6247ffb5d219bc224b31cf4b4957d11.jpeg)
CountDownLatch类图
CountDownLatch有个内部类Sync,Sync继承AQS(AbstractQueuedSynchronizer,抽象的队列同步器),本质也是由AQS来提供锁的相关功能。CountDownLatch内部最重要的两个方法是await()和countDown(),调用countDownLatch.await()方法的线程会被中断,放入等待队列中,等待被唤醒;调用countDownLatch.countDown()方法的线程则会将CountDownLatch持有的锁个数减1操作,当减到0时,会唤醒在等待队列中的线程。
CountDownLatch在实例化时可以指定锁的个数,即count参数,是一个volatile变量修饰的共享内存参数。
![b04bfd64723faddf7da8bc78299549b8.png](https://i-blog.csdnimg.cn/blog_migrate/e3ed82e4119b2bb350159a6508b013be.jpeg)
CountDownLatch构造方法
下面来重点看一下await()方法,await()方法的调用层次关系如下。
CountDownLatch下的的await()public void await() throws InterruptedException {sync.acquireSharedInterruptibly(1);//调用AbstractQueuedSynchronizer下的acquireSharedInterruptibly()}
AbstractQueuedSynchronizer下的acquireSharedInterruptibly()public final void acquireSharedInterruptibly(int arg) throws InterruptedException { if (Thread.interrupted()) throw new InterruptedException(); if (tryAcquireShared(arg) < 0)//方法的含义是判断CountDownLatch锁的个数是否为0,为0返回1, //不为0返回-1,返回-1时,进入到if逻辑里面,去执行是否挂起当前线程的操作 doAcquireSharedInterruptibly(arg);//执行挂起当前线程操作,并把当前线程放入等待队列中 }
CountDownLatch下的的tryAcquireShared()protected int tryAcquireShared(int acquires) { return (getState() == 0) ? 1 : -1;//锁的个数不为0,返回-1,为0返回1}
下面来重点看一下countDown()方法,countDown()方法的调用层次关系如下。
countDown()public void countDown() { sync.releaseShared(1);}
AbstractQueuedSynchronizer下的releaseShared()public final boolean releaseShared(int arg) { if (tryReleaseShared(arg)) {//进行锁个数减1操作,如果返回true,代表锁个数为0,紧接着进行 //等待队列线程唤醒的操作 doReleaseShared(); //执行具体的等待队列线程唤醒操作 return true; } return false;}
CountDownLatch下的的tryReleaseShared()protected boolean tryReleaseShared(int releases) { for (;;) { int c = getState(); //获取当前锁个数 if (c == 0)//如果锁个数已经为0,则不需要进行减1操作,也不需要唤醒等待队列线程,因为已经执行过唤醒 return false; int nextc = c-1;//锁个数-1 if (compareAndSetState(c, nextc))//更新锁个数 return nextc == 0; //当锁个数为0时,返回true,紧接着执行唤醒队列中线程的操作 }}
以上就是CountDownLatch倒计时锁的方法说明。
下面写个Demo示例。
![ab8c1ceabd79f835195b680dea1706a8.png](https://i-blog.csdnimg.cn/blog_migrate/e37e6a9f5f397bec8a47ccc359880917.jpeg)
结果:
![8c3e663206539c687b116ac889ac09e1.png](https://i-blog.csdnimg.cn/blog_migrate/95497cd0069bc4d6e9f09eaa4d50882b.jpeg)