标题:
Java并发编程-AbstractQueuedSynchronizer源码分析(5)
[打印本页]
作者:
look_w
时间:
2019-1-17 19:22
标题:
Java并发编程-AbstractQueuedSynchronizer源码分析(5)
01
final
boolean
acquireQueued(
final
Node node,
int
arg) {
02
boolean
failed =
true
;
03
try
{
04
boolean
interrupted =
false
;
05
for
(;;) {
06
final
Node p =
node.predecessor();
07
if
(p == head &&
amp; tryAcquire(arg)) {
08
setHead(node);
09 p.next =
null
;
//
help GC
10 failed =
false
;
11
return
interrupted;
12
}
13
if
(shouldParkAfterFailedAcquire(p, node) &&
amp;
14
parkAndCheckInterrupt())
15 interrupted =
true
;
16
}
17 }
finally
{
18
if
(failed)
19
cancelAcquire(node);
20
}
21 }[url=]
[/url]
上述逻辑主要包括:
1. 获取当前节点的前驱节点;
需要获取当前节点的前驱节点,而头结点所对应的含义是当前站有锁且正在运行。
2. 当前驱节点是头结点并且能够获取状态,代表该当前节点占有锁;
如果满足上述条件,那么代表能够占有锁,根据节点对锁占有的含义,设置头结点为当前节点。
3. 否则进入等待状态。
如果没有轮到当前节点运行,那么将当前线程从线程调度器上摘下,也就是进入等待状态。
这里针对acquire做一下总结:
1. 状态的维护;
需要在锁定时,需要维护一个状态(int类型),而对状态的操作是原子和非阻塞的,通过同步器提供的对状态访问的方法对状态进行操纵,并且利用compareAndSet来确保原子性的修改。
2. 状态的获取;
一旦成功的修改了状态,当前线程或者说节点,就被设置为头节点。
3. sync队列的维护。
在获取资源未果的过程中条件不符合的情况下(不该自己,前驱节点不是头节点或者没有获取到资源)进入睡眠状态,停止线程调度器对当前节点线程的调度。
这时引入的一个释放的问题,也就是说使睡眠中的Node或者说线程获得通知的关键,就是前驱节点的通知,而这一个过程就是释放,释放会通知它的后继节点从睡眠中返回准备运行。
下面的流程图基本描述了一次acquire所需要经历的过程:
如上图所示,其中的判定退出队列的条件,判定条件是否满足和休眠当前线程就是完成了自旋spin的过程。
欢迎光临 电子技术论坛_中国专业的电子工程师学习交流社区-中电网技术论坛 (http://bbs.eccn.com/)
Powered by Discuz! 7.0.0