标题:
Java并发编程-AbstractQueuedSynchronizer源码分析(9)
[打印本页]
作者:
look_w
时间:
2019-1-17 19:27
标题:
Java并发编程-AbstractQueuedSynchronizer源码分析(9)
public final void acquireShared(int arg)调用该方法能够以共享模式获取状态,共享模式和之前的独占模式有所区别。以文件的查看为例,如果一个程序在对其进行读取操作,那么这一时刻,对这个文件的写操作就被阻塞,相反,这一时刻另一个程序对其进行同样的读操作是可以进行的。如果一个程序在对其进行写操作,那么所有的读与写操作在这一时刻就被阻塞,直到这个程序完成写操作。
以读写场景为例,描述共享和独占的访问模式,如下图所示:
上图中,红色代表被阻塞,绿色代表可以通过。
[url=]
[/url]
01
public
final
void
acquireShared(
int
arg) {
02
if
(tryAcquireShared(arg) < 0) doAcquireShared(arg); }
private
void
doAcquireShared(
int
arg) {
final
Node node = addWaiter(Node.SHARED);
boolean
failed =
true
;
try
{
boolean
interrupted =
false
;
for
(;;) {
final
Node p = node.predecessor();
if
(p == head) {
int
r = tryAcquireShared(arg);
if
(r >= 0
) {
03
setHeadAndPropagate(node, r);
04 p.next =
null
;
//
help GC
05
if
(interrupted)
06
selfInterrupt();
07 failed =
false
;
08
return
;
09
}
10
}
11
if
(shouldParkAfterFailedAcquire(p, node) &&
amp;
12
parkAndCheckInterrupt())
13 interrupted =
true
;
14
}
15 }
finally
{
16
if
(failed)
17
cancelAcquire(node);
18
}
19 }[url=]
[/url]
上述逻辑主要包括:
1. 尝试获取共享状态;
调用tryAcquireShared来获取共享状态,该方法是非阻塞的,如果获取成功则立刻返回,也就表示获取共享锁成功。
2. 获取失败进入sync队列;
在获取共享状态失败后,当前时刻有可能是独占锁被其他线程所把持,那么将当前线程构造成为节点(共享模式)加入到sync队列中。
3. 循环内判断退出队列条件;
如果当前节点的前驱节点是头结点并且获取共享状态成功,这里和独占锁acquire的退出队列条件类似。
4. 获取共享状态成功;
在退出队列的条件上,和独占锁之间的主要区别在于获取共享状态成功之后的行为,而如果共享状态获取成功之后会判断后继节点是否是共享模式,如果是共享模式,那么就直接对其进行唤醒操作,也就是同时激发多个线程并发的运行。
5. 获取共享状态失败。
通过使用LockSupport将当前线程从线程调度器上摘下,进入休眠状态。
对于上述逻辑中,节点之间的通知过程如下图所示:
上图中,绿色表示共享节点,它们之间的通知和唤醒操作是在前驱节点获取状态时就进行的,红色表示独占节点,它的被唤醒必须取决于前驱节点的释放,也就是release操作,可以看出来图中的独占节点如果要运行,必须等待前面的共享节点均释放了状态才可以。而独占节点如果获取了状态,那么后续的独占式获取和共享式获取均被阻塞。
欢迎光临 电子技术论坛_中国专业的电子工程师学习交流社区-中电网技术论坛 (http://bbs.eccn.com/)
Powered by Discuz! 7.0.0