AQS源码解析
2021-09-14 14:54:00 0 举报
AQS源码解析
作者其他创作
大纲/内容
线程B
①:将head节点指向线程B所在的节点
tail节点是否为null
state=0持有线程:null
A、B、C三个线程依次执行lock.lock()方法上锁:
执行lock()方法:
acquire(1)
④
true
线程C:将前指针设置为B线程,将线程C设置为尾节点,并将前一个节点的尾指针设置为C线程
⑤:将哨兵的节点的尾指针指向线程B
线程B进来,第一次循环,发现tail为null,此时创建新的head节点,并将head新节点赋值给tail节点第二次循环,将B节点的前节点设置为刚才创建的节点,并将B节点作为tail节点,将新节点的下一个节点设置为B节点,并返回创建的新节点
⑤:旧的哨兵节点没有指针指向,等待回收
调用acquireQueued()方法,将线程B的waitStatus状态从0改为-1,并调用part()方法等待唤醒,此时线程C进入等待唤醒队列
false
tail
next
线程B进来后,tail为null,执行enq方法后面线程C进来,tail节点为B节点了,将C节点的前节点设置是为B节点,将tail节点设置为C节点,将B节点的下一个节点设置为C节点,返回C节点
https://blog.csdn.net/XJ0927/article/details/113140064https://www.processon.com/view/5fb6590f7d9c0857dda50442?fromnew=1
线程A:通过CAS拿到锁,并修改state的值为1,并将持有线程改为线程A
⑥:线程C来了,将线程C的前指针指向线程B
①
哨兵节点
head
调用acquireQueued()方法,将哨兵节点的waitStatus状态从0改为-1,并调用part()方法等待唤醒,此时线程B进入等待唤醒队列
待回收的哨兵节点
②
prev
sync.lock()
③:将线程B的前指针指向哨兵节点
②:将线程B节点所在的线程设置为null,成为新的哨兵节点
重回acquireQueued()方法,当时线程B就是在此自旋阻塞等待唤醒的
tryRelease()
非公平锁
④:将线程B通过CAS设置为尾节点
再次执行tryAcuire()方法
拿到head节点,当前线程为A,此时head节点时哨兵节点,修改哨兵节点的waitStatus从-1为0,并唤醒head节点的下一个节点即线程B,此时线程B就可以加锁了
enq方法
③
将前哨兵节点的下一个节点设置为null
②:将哨兵节点设置尾节点
CAS获取锁
unparkSuccessor()
④:将旧的哨兵节点的后指针设置为null
流程图:
state=1持有线程:线程A
⑧:将线程B的尾指针指向线程C
③:将新的哨兵节点前指针设置为null
线程C
线程A
addWaiter()
A释放锁,唤醒B加锁:
⑦:将线程C通过CAS设置为尾节点
队列节点
⑤
AQS目前值:
⑥
abstract void lock();
parkAndCheckInterrupt()方法
shouldParkAfterFailedAcquire(前node节点,前node节点)
AQS中的release()
setHead(线程B)
参考地址:
②哨兵节点
⑤哨兵节点(待回收)
流程图显示:
tryAcquire()
⑧
state=1持有线程:线程B
前哨兵节点没有指针指向,等待GC时回收
ReentrantLock中的Sync
执行unlock()方法
①:线程B来了,发现尾节点为null,创建哨兵节点,并将哨兵节点通过CAS设置为头节点
说明获取了锁,直接返回
线程B:进来发现state不为1,持有线程不为B线程,创建哨兵节点,将头节点设置为哨兵节点,并将哨兵节点设置为哨兵节点,将线程B的前指针指向哨兵节点,将尾节点设置为B线程,并将前一个节点的尾指针指向B线程
线程B,执行tryAcquire()方法,拿到锁
AQS初始值:
sync.release(1)
线程B进来,会进入等待唤醒的队列,线程C进来也是如此
线程A,执行unlock()方法
⑦
0 条评论
回复 删除
下一页