概述
上文分析了独占模式下的acquire实现,本章分析一下共享模式下的acquireShared实现
acquireShared
每个线程都会尝试去获取共享锁,只有获取失败的才会进入doAcquireShared方法
public final void acquireShared(int arg) {
if (tryAcquireShared(arg) < 0)
doAcquireShared(arg);
}
doAcquireShared
这里共享锁与独占锁的实现类似
首先,也是判断当前节点是否是head节点的有效后继节点,如果是的话,当前节点就回去尝试获取一次共享锁,如果获取成功就调用setHeadAndPropagate继续传播,如果不是head节点的有效后继节点,就判断当前节点是否应该阻塞,剩下的逻辑与acquire类似就不再分析,重点关注一下setHeadAndPropagate的实现
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);
}
setHeadAndPropagate
设置head节点的同时根据propagate值做逻辑处理,注意进入此方法前,一定是由于有线程调用了doReleaseShared方法,而在该方法执行后的head的waitStatus状态只能为0或者为propagate
1.h=null 和 (h=head)=null只是为了防止null指针异常,一般情况下是不会出现这俩种情况的,重点关注别的判断
如果propagate>0说明还有共享锁可以获取,那么直接读取当前节点的后继节点,如果后继节点为null或者是共享模式才调用doReleaseShared方法,前面的章节分析中我们知道这个方法就是在一定的条件下唤醒head的后继节点,
2.如果propagate=0 且 旧节点的waitStatus<0,根据上面的分析可知此时head的waitStatus为propagate,同时,propagate=0也只是说明线程执行到这里时没有锁可获取,但是在之后有另一个线程释放了锁,导致head的waitStatus<0,所以也需要调用doReleaseShared来唤醒head的后继节点继续来尝试获取锁
3.如果propagate=0 且 旧head节点的waitStatus=0 且新的head节点的waitStatus<0,旧的head节点为0,很正常,因为唤醒该新节点时本就会把旧的head状态设为0,而新节点被设置为head后,之前本就处于SIGNAL状态来阻塞它的后继节点,它的状态自然小于0,因此也就造成了不必要的唤醒
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 either before
* or after setHead) 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 ||
(h = head) == null || h.waitStatus < 0) {
Node s = node.next;
if (s == null || s.isShared())
doReleaseShared();
}
}
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。