说明
使用方式参考:https://www.cnblogs.com/LQBlog/p/8983019.html
初始化
main
public static void main(String[] args) throws InterruptedException { //<1>初始化 CountDownLatch countDownLatch=new CountDownLatch(3); }
<1>初始化
public CountDownLatch(int count) { if (count < 0) throw new IllegalArgumentException("count < 0"); //初始化内部类的对象 Sync 改类继承AQS this.sync = new CountDownLatch.Sync(count); } private static final class Sync extends AbstractQueuedSynchronizer { private static final long serialVersionUID = 4982264981922014374L; Sync(int count) { //调用父类的设置所属状态 这里就表名锁以及被持有量额 setState(count); } }
await等待
main
public static void main(String[] args) throws InterruptedException { //初始化 默认设置AQS state为3 表示锁已经被持有 CountDownLatch countDownLatch=new CountDownLatch(3); //<1>本质是加锁 countDownLatch.await(); }
1.因为初始化设置了栅栏数量 AQS state
2.实现获取共享锁的是判断 state是否>0 大于0则获取失败 交给AQS 放入CLH队列等待
<1>await
public void await() throws InterruptedException { //<2>调用父类获取AQS方法 sync.acquireSharedInterruptibly(1); }
<2>doAcquireSharedInterruptibly
详情可以参考《AQS源码阅读》
/** * Acquires in shared interruptible mode. * @param arg the acquire argument */ private void doAcquireSharedInterruptibly(int arg) throws InterruptedException { //创建共享节点 并插入队列 final AbstractQueuedSynchronizer.Node node = addWaiter(AbstractQueuedSynchronizer.Node.SHARED); boolean failed = true; try { //自旋 for (;;) { //获得节点的上一个节点 final AbstractQueuedSynchronizer.Node p = node.predecessor(); //如果他的节点就是节点头 尝试获取锁 因为并发情况节点头可能释放了 if (p == head) { //<3>子类实现获取共享锁方法模板模式 int r = tryAcquireShared(arg); if (r >= 0) { //重新设节点头 并尝试唤醒其他等待节点 setHeadAndPropagate(node, r); p.next = null; // help GC failed = false; return; } } //如果前一个节点p的状态是Node.SIGNAL,就是调用<6>parkAndCheckInterrupt方法阻塞当前线程 if (shouldParkAfterFailedAcquire(p, node) && parkAndCheckInterrupt()) throw new InterruptedException(); } } finally { if (failed) //<此时前一个节点pred的状态只能是0或者PROPAGATE,不可能是CONDITION状态 // CONDITION(这个是特殊状态,只在condition列表中节点中存在,CLH队列中不存在这个状态的节点) // 将前一个节点pred的状态设置成Node.SIGNAL,这样在下一次循环时,就是直接阻塞当前线程 cancelAcquire(node); } }
<3>tryAcquireShared
java.util.concurrent.CountDownLatch.Sync#tryAcquireShared
protected int tryAcquireShared(int acquires) { //获取state 前面我们默认值设置的3 所以await是获取不到的 所以加入AQS队列 return (getState() == 0) ? 1 : -1; }
countDown释放
main
public static void main(String[] args) throws InterruptedException { //初始化 默认设置AQS state为3 表示锁已经被持有 CountDownLatch countDownLatch=new CountDownLatch(3); //<1>本质是释放锁 countDownLatch.countDown(); }
1.每次释放 栅栏数量-1(AQS sate) 如果state
2.当state数量大于==0 则返回释放成功 交给AQS 唤醒AQS阻塞队列 这个时候因为state等于0 所以都获取成功锁
<1>countDown
public void countDown() { //<2>调用内部内对象释放共享锁的方法 继承自AQS sync.releaseShared(1); }
<2>releaseShared
可以参考《AQS源码阅读》
// 释放共享锁 public final boolean releaseShared(int arg) { // <3>模板模式 抽象方法尝试释放共享锁 if (tryReleaseShared(arg)) { //唤醒等待共享锁的线程 doReleaseShared(); return true; } return false; }
<3>tryReleaseShared
java.util.concurrent.CountDownLatch.Sync#tryReleaseShared
protected boolean tryReleaseShared(int releases) { //自旋 for (;;) { //获得状态 int c = getState(); //如果已经等于0 返回false if (c == 0) return false; int nextc = c-1; //cas设置状态-1 当成功并且等于0 表示释放成功 会唤醒阻塞线程 if (compareAndSetState(c, nextc)) return nextc == 0; } }