AbstractQueuedSynchronizer(AQS)共享锁的获取
2022-05-02 14:47:06 0 举报
Java AbstractQueuedSynchronizer(AQS)共享锁的获取和释放
作者其他创作
大纲/内容
获取当前节点前驱状态不为取消的节点
创建Node节点并插入竞争队列
yes更新成功
yes为空
将前驱节点的next设置为该后继节点
no
调用cancelAcquire(node)
doAcquireShared(arg)
返回节点node
判断当前节点是否尾节点?
yes
yes非取消
唤醒后面等待的节点
获取当前头节点head
CAS将头节点等待状态更新为Node.PROPAGATE
CAS操作是否成功?
获取当前节点的前驱节点
enq(node)死循环插入,CAS替换尾指针原子性插入Node节点直到插入成功退出
后继节点为空?
是否出现异常?
CAS将头节点等待状态更新为0
返回值大于等于0?
循环查询下一个状态不大于0的节点
响应中断版本:直接退出循环
public final void acquireSharedInterruptibly(int arg) throws InterruptedException { if (Thread.interrupted()) throw new InterruptedException(); if (tryAcquireShared(arg) < 0) doAcquireSharedInterruptibly(arg); }
判断状态是否大于0(是否取消Node.CANCEL)
后继节点是否共享?
头节点是否为空且不等于尾节点?
前驱节点是否为头节点?
获取前驱节点的状态waitStatus
获取当前节点的后继节点
unparkSuccessor(h)唤醒后继节点
doAcquireSharedInterruptibly(arg)
当前节点的后继节点状态是取消?
public final void acquireShared(int arg)获取共享锁,忽略中断,将中断状态位返回给上层
yes获取锁失败
前驱节点状态CAS设置为SIGNAL是否成功?
修改前驱节点状态为SIGNAL
前驱节点状态是否为Node.SIGNAL?或者
头节点等待状态是否为Node.SIGNAL
yes为空(新头节点为空)
获取当前节点等待状态
成功获取锁后的处理(绿色部分):1、将当前节点更新为头节点;2、唤醒后面等待的节点唤醒条件:(1)原先的头节点或者当前头节点(新头节点)为空或者等待状态不为取消(2)当前节点的后继节点为空或者后继节点为共享模式Node.SHARD
yes成功获取锁
doReleaseShared()唤醒后面等待的节点
后继节点是否为空?
当前节点是否取消
从尾节点从后向前找最开始那个等待状态小于等于0的节点
创建Node对象,保存当前线程的引用
addWaiter(Node.SHARED)
tryAcquireShared(arg)抽象方法,由子类实现,返回int值
yes头节点发生变化
no获取锁失败
无限循环等待
判断此过程中线程是否被中断?
忽略中断版本
响应中断版本
前驱节点为头节点,则需要唤醒后继节点
头节点等待状态是否为0?
获取锁失败后的处理(深红色部分):1、判断是否允许阻塞允许阻塞的条件:确保当前节点的前驱节点存在SHARD模式的节点才允许阻塞2、进行阻塞,无限循环等待
no非头节点
判断当前节点是否为空?
将当前节点状态设置为Node.CANCEL取消
返回true表明线程通过中断唤醒设置为中断为为true
没有需要唤醒的节点了退出无限循环
public final void acquireSharedInterruptibly(int arg)获取共享锁,响应中断,抛出中断异常
no更新失败
结束
Node node
返回是否true?
是否为Node.SIGNAL
CAS更新是否成功?
public final void acquireShared(int arg) { if (tryAcquireShared(arg) < 0) doAcquireShared(arg); }
表明前驱节点会唤醒后续节点所以当前节点可以放下阻塞
设置中断位
返回值小于0?
尾插法插入FIFO双向队列
原始头节点是否为空
取消获取锁流程
将前驱节点的后继next指针设置为空
返回false表示当前线程不可park阻塞
成功获取共享锁
头节点是否发生变化?
调用unparkSuccessor(node)唤醒后继节点
释放当前节点引用的线程对象(node的线程引用设置为空)
当前节点是否为空?
原始头节点waitStatu小于0(即是不是取消状态)
no没有改变
获取头节点的等待状态waitStatus
调用parkAndCheckInterrupt()将当前线程设置为可中断的等待
成功取消锁获取流程
快速插入等待队列中,CAS替换尾指针tail
等待状态小于0?
后继节点等待状态大于0
小结:共享锁与互斥锁的主要区别:(1)互斥锁成功获取后不需要唤醒后继节点(2)共享锁成功获取后需要唤醒后继节点
获取其后继节点
返回true响应中断,抛出中断异常
CAS更新等待状态为0
前驱节点引用线程是否为空?
获取后继节点
前驱节点非取消?
记录当前头节点,并将当前节点设置为头节点
是否成功获取锁?(tryAcquireShared(arg)返回值大于0?)
CAS替换其前驱节点为尾节点(非取消状态)
返回true表示当前线程可以阻塞
取消锁获取流程
修改前驱节点的后续为新找到的状态不大于0的节点
唤醒该节点
开始
0 条评论
下一页