高并发编程的成神之路--3.AbstractQueuedSynchronized(AQS)源码底层分析

AbstractQueuedSynchronized(AQS)详解

在研究一个类的时候先读它的原代码这样能有一个整体的认识(下面只是截取了部分,需要看的自己把后面的看完)

 源码分析:

查看ReentrantLock类的lock()方法

可以看到它本身调用的是同步方法

高并发编程的成神之路--3.AbstractQueuedSynchronized(AQS)源码底层分析_第1张图片

由于存在公平锁和非公平锁 

 高并发编程的成神之路--3.AbstractQueuedSynchronized(AQS)源码底层分析_第2张图片

 高并发编程的成神之路--3.AbstractQueuedSynchronized(AQS)源码底层分析_第3张图片

 高并发编程的成神之路--3.AbstractQueuedSynchronized(AQS)源码底层分析_第4张图片

在这个里面存在着一个可重入锁的概念。 

 高并发编程的成神之路--3.AbstractQueuedSynchronized(AQS)源码底层分析_第5张图片

 非公平锁:

还是一个之前手写可重入锁的概念,获取当前线程,修改状态值c,然后设置独占线程

高并发编程的成神之路--3.AbstractQueuedSynchronized(AQS)源码底层分析_第6张图片

 在重入之后可以直接返回true继续执行,而不会锁死

高并发编程的成神之路--3.AbstractQueuedSynchronized(AQS)源码底层分析_第7张图片

如果拿到锁了,就不执行后面的,没拿到继续执行后面的语句

高并发编程的成神之路--3.AbstractQueuedSynchronized(AQS)源码底层分析_第8张图片

 这里面就相比来说比较复杂

高并发编程的成神之路--3.AbstractQueuedSynchronized(AQS)源码底层分析_第9张图片

Node.EXCLUSIVE独占 

 高并发编程的成神之路--3.AbstractQueuedSynchronized(AQS)源码底层分析_第10张图片

 就是一个链表,将进入的新的结点添加进去

 高并发编程的成神之路--3.AbstractQueuedSynchronized(AQS)源码底层分析_第11张图片

高并发编程的成神之路--3.AbstractQueuedSynchronized(AQS)源码底层分析_第12张图片

 enq()方法,当没有尾节点,那就将node作为尾节点存放

高并发编程的成神之路--3.AbstractQueuedSynchronized(AQS)源码底层分析_第13张图片

 高并发编程的成神之路--3.AbstractQueuedSynchronized(AQS)源码底层分析_第14张图片

上面我们已经将所有等待的线程放入到等待双向链表中,但是并没有阻塞它

回到 acquireQueued()

高并发编程的成神之路--3.AbstractQueuedSynchronized(AQS)源码底层分析_第15张图片

 如果当前结点(等待双向链表的尾节点)的前面一个结点是头结点,那就将它踢出去,将自己设置为头结点

高并发编程的成神之路--3.AbstractQueuedSynchronized(AQS)源码底层分析_第16张图片

 如果当前双链表中存在三个及三个以上结点,执行下面的语句

高并发编程的成神之路--3.AbstractQueuedSynchronized(AQS)源码底层分析_第17张图片

如果为等待状态返回true 

 高并发编程的成神之路--3.AbstractQueuedSynchronized(AQS)源码底层分析_第18张图片

取消状态

高并发编程的成神之路--3.AbstractQueuedSynchronized(AQS)源码底层分析_第19张图片

 高并发编程的成神之路--3.AbstractQueuedSynchronized(AQS)源码底层分析_第20张图片

 移除掉取消状态的结点(判断的是node结点的前一个结点)

高并发编程的成神之路--3.AbstractQueuedSynchronized(AQS)源码底层分析_第21张图片

 如果是小于0的,就将结点设置为等待

高并发编程的成神之路--3.AbstractQueuedSynchronized(AQS)源码底层分析_第22张图片

ShouldParkAfterFailAcquire()方法只有当结点是singal(等待状态的时候)返回true。

继续执行后面的

高并发编程的成神之路--3.AbstractQueuedSynchronized(AQS)源码底层分析_第23张图片

 让当前线程真正处于等待状态

高并发编程的成神之路--3.AbstractQueuedSynchronized(AQS)源码底层分析_第24张图片

 现在的话基本上加锁流程就结束了。

 

现在看解锁:

高并发编程的成神之路--3.AbstractQueuedSynchronized(AQS)源码底层分析_第25张图片

 首先就是进行c的状态-1

高并发编程的成神之路--3.AbstractQueuedSynchronized(AQS)源码底层分析_第26张图片

 如果当前线程不是独占线程(之前没有进行lock)

高并发编程的成神之路--3.AbstractQueuedSynchronized(AQS)源码底层分析_第27张图片

 c其实就是一个计数器,记录当前线程拿了几个锁,拿一个锁(lock)+1,释放一个锁(unlock)-1

如果c为0说明就没有线程拿锁,就可以直接释放独占线程资源

高并发编程的成神之路--3.AbstractQueuedSynchronized(AQS)源码底层分析_第28张图片

 回到release方法

有独占线程tryRelease就返回false,没有独占线程就返回true

高并发编程的成神之路--3.AbstractQueuedSynchronized(AQS)源码底层分析_第29张图片

 头结点不为null,不等于0说明当前头结点为等待状态

高并发编程的成神之路--3.AbstractQueuedSynchronized(AQS)源码底层分析_第30张图片

 这行来说意义不大,不需要研究

高并发编程的成神之路--3.AbstractQueuedSynchronized(AQS)源码底层分析_第31张图片

node的下一个结点为空,那就将尾节点赋给它的下一个结点

高并发编程的成神之路--3.AbstractQueuedSynchronized(AQS)源码底层分析_第32张图片

 如果不为空,就叫醒当前结点上的线程去争夺CPU资源

高并发编程的成神之路--3.AbstractQueuedSynchronized(AQS)源码底层分析_第33张图片

总结:AQS主要是通过一条双向链表和一个状态值来维护的 

你可能感兴趣的:(高并发编程)