共享模式acquire实现流程
上文我们讲授了AbstractQueuedSynchronizer独有模式的acquire实现流程,本文一气呵成继承看一下AbstractQueuedSynchronizer共享模式acquire的实现流程。持续两篇文章的进修,也可以比拟独有模式acquire和共享模式acquire的区别,劳务派遣管理系统,加深对付AbstractQueuedSynchronizer的领略。
先看一下共享模式acquire的实现,要领为acquireShared和acquireSharedInterruptibly,两者不同不大,区别就在于后者有间断处理惩罚,以acquireShared为例:
public final void acquireShared(int arg) {
if (tryAcquireShared(arg) < 0)
doAcquireShared(arg);
}
这里就能看出第一个不同来了:独有模式acquire的时候子类重写的要领tryAcquire返回的是boolean,等于否tryAcquire乐成;共享模式acquire的时候,返回的是一个int型变量,判定是否<0。doAcquireShared要领的实现为:
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) {
setHeadAndPropagate(node, r);
p.next = null; // help GC
if (interrupted)
selfInterrupt();
failed = false;
return;
}
}
if (shouldParkAfterFailedAcquire(p, node) &&
parkAndCheckInterrupt())
interrupted = true;
}
} finally {
if (failed)
cancelAcquire(node);
}
}
我们来阐明一下这段代码做了什么:
确实,共享模式下的acquire和独有模式下的acquire大部门逻辑差不多,最大的不同在于tryAcquireShared乐成之后,独有模式的acquire是直接将当前节点配置为head节点即可,共享模式会执行setHeadAndPropagate要领,顾名思义,即在配置head之后多执行了一步propagate操纵。setHeadAndPropagate要领源码为:
private void setHeadAndPropagate(Node node, int propagate) {
Node h = head; // Record old head for check below
setHead(node);
/*
* Try to signal next queued node if:
* Propagation was indicated by caller,
* or was recorded (as h.waitStatus) by a previous operation
* (note: this uses sign-check of waitStatus because
* PROPAGATE status may transition to SIGNAL.)
* and
* The next node is waiting in shared mode,
* or we don't know, because it appears null
*
* The conservatism in both of these checks may cause
* unnecessary wake-ups, but only when there are multiple
* racing acquires/releases, so most need signals now or soon
* anyway.
*/
if (propagate > 0 || h == null || h.waitStatus < 0) {
Node s = node.next;
if (s == null || s.isShared())
doReleaseShared();
}
}
第3行的代码配置重设head,第2行的代码由于第3行的代码要重设head,因此先界说一个Node型变量h得到原head的地点,这两行代码很简朴。
第19行~第23行的代码是独有锁和共享锁最纷歧样的一个处所,我们再看独有锁acquireQueued的代码:
final boolean acquireQueued(final Node node, int arg) {
boolean failed = true;
try {
boolean interrupted = false;
for (;;) {
final Node p = node.predecessor();
if (p == head && tryAcquire(arg)) {
setHead(node);
p.next = null; // help GC
failed = false;
return interrupted;
}
if (shouldParkAfterFailedAcquire(p, node) &&
parkAndCheckInterrupt())
interrupted = true;
}
} finally {
if (failed)
cancelAcquire(node);
}
}
这意味着独有锁某个节点被叫醒之后,它只需要将这个节点配置成head就完事了,而共享锁纷歧样,某个节点被配置为head之后,假如它的后继节点是SHARED状态的,那么将继承通过doReleaseShared要领实验往后叫醒节点,实现了共享状态的向后流传。
共享模式release实现流程