@toc
一个同步辅助类,在完成一组正在其他线程中执行的操作之前,它允许一个或多个线程一直等待。
用给定的计数 初始化 CountDownLatch。由于调用了 countDown() 方法,所以在当前计数到达零之前,await 方法会一直受阻塞。之后,会释放所有等待的线程,await 的所有后续调用都将立即返回。这种现象只出现一次——计数无法被重置。如果需要重置计数,请考虑使用 CyclicBarrier。
如果传入的值小于0,那么抛出异常。 否则,初始化内部的Sync
CountDownLatch内部的Sync也是继承于AQS的。 Sync的构造,传入的值是初始化AQS的锁持有线程数量的。
CountDownLatch的await方法是等待通知,将当前线程阻塞,直到锁空闲。(或者说计数器倒数至0) AQS的acquireSharedInterruptibly方法请看 Java基础–AQS原理 的5.6.4小节。 调用AQS的acquireSharedInterruptibly方法。 await方法响应中断,而且计数器锁是一个共享锁。 是共享锁,就需要AQS的子类Sync实现tryAcquireShared和tryReleaseShared方法。 在自旋中尝试获取共享锁,尝试获取共享锁,调用的是CountDownLatch的Sync实现的tryAcquireShared方法。 只有锁空闲,才允许等待竞争队列中的线程执行。 换句话说,当计数器倒数没到0时,线程需要等待计数器归0.
带有超时时间的等待,响应中断。 调用了AQS的tryAcquireSharedNanos方法。 AQS的tryAcquireSharedNanos方法请看 Java基础–AQS原理 的5.6.5小节。 带有超时的等待,也是调用CountDownLatch的Sync实现的tryAcquireShared方法的。
计数器锁值减1. 直接调用AQS的releaseShared方法。 AQS的releaseShared方法请看 Java基础–ReentrantReadWriterLock–重入读写锁 的2.1.5小节。 AQS的releaseShared方法会调用AQS子类实现的tryReleaseShard方法的。 也就是CountDownLatch的Sync实现的tryReleaseShared方法。 自旋将锁持有数量减1,也就是将计数器锁的值减1. 如果锁状态已经是0,表示现在已经无法继续减下去了。不过也不会抛出异常,因为countDown是没有返回值的。 如果锁状态不是0,那么将锁状态减1,最后返回锁是否空闲。 如果锁空闲,那么等待竞争队列中的线程都可以再次调用tryAcquireShared方法尝试获取锁。 此时锁空闲,锁状态为0,也就是,等待竞争队列中每一个线程都能获取锁。 请注意,CountDownLatch的计数器值为0之后,在无法恢复的。 CountDownLatch只能做减法。
获取当前计数器锁的值。即获取锁状态值。 CountDownLatch调用其内部的Sync的getCount方法。 CountDownLatch的Sync的getCount方法调用AQS的getState方法。
执行结果 开始后,await线程都被阻塞了,然后count down线程将计数器锁的值减小,直到为0. 此时await线程就都被唤醒继续执行了。
需要注意一点,在输出中 ->左边可能相等,但是右边一定不相等。 因为右边使用cas进行设置的,保证线程安全。