java.util.concurrent包图文源码解析(一)——CountDownLatch

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/chenzitaojay/article/details/75175029

好久没有写博客了,四个字:贵在坚持!!!
从JAVA并发开始,所有的博文都结合源码,什么事情知道原理,得心应手。
java.util.concurrent包是线程控制框架,所谓的框架,就是提供有限的接口去实现极可能多的控制,大了说Spring,小了说线程池。
废话不多说,先来张图:
这里写图片描述

代码剖析 CountDownLatch

CountDownLatch的使用如下:

//同一个latch也可以被很多 线程持有,那么唤醒的时候需要依次唤醒
CountDownLatch latch=new CountDownLatch(2);  
latch.await();
doSomething();
latch.countDown();
doSomethind();

latch.await() 加入阻塞队列

public void await() throws InterruptedException {
        sync.acquireSharedInterruptibly(1);
}
//执行的是AbstractQueuedSynchronizer的acquireSharedInterruptibly()
public final void acquireSharedInterruptibly(int arg)
     throws InterruptedException {
    if (Thread.interrupted())//如果当前线程被interrupt,那么抛出异常,相当于阻塞的退出
        throw new InterruptedException();
    if (tryAcquireShared(arg) < 0)//在各个子类Sync中实现
        doAcquireSharedInterruptibly(arg);
}
//tryAcquireShared在CountDownLatch的内部类Sync中实现:
/**
* 阻塞的条件,如果当前的state>0那么就一直阻塞。
* 阻塞的代码在AQS的doAcquireSharedInterruptibly
*/
protected int tryAcquireShared(int acquires) {
     return (getState() == 0) ? 1 : -1;
}
//下面是阻塞代码doAcquireSharedInterruptibly

这里写图片描述

加入CLH队列的代码如下:
这里写图片描述

上面代码的思想:构造双向链表,其中head节点是一个没有没有thread的节点。其中属性
waitStatus
值为1,表示当前的线程被取消;
值为-1,表示当前节点的后继节点包含的线程需要运行,也就是unpark;
值为-2,表示当前节点在等待condition,也就是在condition队列中;
值为-3,表示当前场景下后续的acquireShared能够得以执行;
值为0,表示当前节点在sync队列中,等待着获取锁。
thread 封装的线程

这里写图片描述

countDown 释放锁

 public void countDown() {
   sync.releaseShared(1);//共享
 }
 会调用AbstractQueuedSynchronizer的releaseShared方法:

这里写图片描述
调用AbstractQueuedSynchronizer的doReleaseShared()方法
这里写图片描述
这段代码逻辑总结:

  1. 如果当前head节点waitStatus==Node.SIGNAL,那么设置waitStatus=0,设置成功唤醒head的后继阻塞node,执行 unparkSuccessor(h);结合阻塞的代码doAcquireSharedInterruptibly,知道如果线程解锁之后会执行这里写图片描述会将head之后的第一个节点设置为head,并设置PROPAGATE,代码如下这里写图片描述 会再次执行doReleaseShared()方法唤醒下一个节点。doReleaseShared()的跳出条件就是这里写图片描述
  2. 如果当前head节点waitStatus==0,那么设置waitStatus=Node.PROPAGATE

    CountDownLatch列子

    这里写图片描述

展开阅读全文

没有更多推荐了,返回首页