JUC_02 AQS工作原理
2021/5/12 10:33:41
本文主要是介绍JUC_02 AQS工作原理,对大家解决编程问题具有一定的参考价值,需要的程序猿们随着小编来一起学习吧!
AQS: state + chl队列完成
Lock.lock()
判断state状态:compareAndSetState
判断state值是否等于0,如果等于0,
说明当前还没有线程获取锁对象资源。
compareAndSetState(0, 1):将state值改为1,
setExclusiveOwnerThread:将当前线程设置为排它线程,其它线程获取锁资源需要等待
获取锁:acquire
acquire(arg) {
if (!tryAcquire(arg) && acquireQueued(
addWaiter(Node.EXCLUSIVE), arg))
selfInterrupt();
}
尝试获取锁:tryAcquire
tryAcquire:
1、判断当前state值是否为0,若是,则并把当前线程设置为排它线程并直接给当前线程放行,
2、判断当前线程是否和排它线程是同一个线程,若是,则将state值进行累加并直接给当前线程放行
添加等待者:addWaiter
1、判断tail节点是否为空
Node pred = tail;
若不为空,则将新加入的node.prev指向pred,再将tail节点改为node节点,最后将pred.next指向node节点
若为空,则执行enq方法(自旋)
第一次:
tail为空:
创建一个新节点作为哨兵节点node
将head节点指向node,然后将
tail节点指向head。
第二次:
tail不为空:
Node t = tail;
将node.prev指向t,
将tail指向node,
最后将t.next指向node
将当前线程封装成Node节点,判断tail节点是否为空,若为空,则指向enq方法(创建哨兵节点),若不为空,直接拼接后续节点。
加入队列:acquireQueued
1、先获取当前节点的前序节点:Node p = node.predecessor(),
若p==head且tryAcquire(arg)为true时,
将当前节点作为head节点,且p.next=null(GC回收)
若不满足,则继续执行:shouldParkAfterFailedAcquire(p, node) &&
parkAndCheckInterrupt()
获取锁成功后将node节点作为head节点,head.next置为nul(GC回收)
final Node p=node.predecessor();
if (p == head && tryAcquire(arg)) {
setHead(node);
p.next = null; // help GC
failed = false;
return interrupted;
}
获取锁失败后进行阻塞操作:shouldParkAfterFailedAcquire && parkAndCheckInterrupt
一、shouldParkAfterFailedAcquire
1、判断Node的waitStatus状态,
将pred节点的waitStatus设置为Node.SIGNAL对应值,用于指示线程执行unpark操作
二、parkAndCheckInterrupt
1、LockSupport.park(this);
将当前线程进行阻塞
Lock.unlock
释放锁:release
尝试释放锁:tryRelease
1、判断当前线程是否是获取锁的排它线程,若不是则抛出异常:IllegalMonitorStateException
2、判断state值是否为0,若等于0则将排它线程置为null
3、更新state状态值
唤醒队列中的节点:unparkSuccessor
一、判断head节点是否为空且waitStatus值是否为0,满足条件:
1、将该节点的waitStatus值重置为0
2、获取下一个节点,若下一个节点s不为空,
则执行LockSupport.unpark(s.thread);
从此唤醒s节点的线程。让它尝试继续获取锁操作
更改waitStatus值状态:compareAndSetWaitStatus
唤醒阻塞线程:unpark(s.thread)
这篇关于JUC_02 AQS工作原理的文章就介绍到这儿,希望我们推荐的文章对大家有所帮助,也希望大家多多支持为之网!
- 2024-11-23增量更新怎么做?-icode9专业技术文章分享
- 2024-11-23压缩包加密方案有哪些?-icode9专业技术文章分享
- 2024-11-23用shell怎么写一个开机时自动同步远程仓库的代码?-icode9专业技术文章分享
- 2024-11-23webman可以同步自己的仓库吗?-icode9专业技术文章分享
- 2024-11-23在 Webman 中怎么判断是否有某命令进程正在运行?-icode9专业技术文章分享
- 2024-11-23如何重置new Swiper?-icode9专业技术文章分享
- 2024-11-23oss直传有什么好处?-icode9专业技术文章分享
- 2024-11-23如何将oss直传封装成一个组件在其他页面调用时都可以使用?-icode9专业技术文章分享
- 2024-11-23怎么使用laravel 11在代码里获取路由列表?-icode9专业技术文章分享
- 2024-11-22怎么实现ansible playbook 备份代码中命名包含时间戳功能?-icode9专业技术文章分享