最近我在学习concurrency.When,我对Semaphore有了更多的了解,我有一些问题。
这是JDK1.8中AbstractQueuedSynchronizer的代码(第727行):
private void setHeadAndPropagate(Node node, int propagate) {
Node h = head; // Record old head for check below
setHead(node);
if (propagate > 0 || h == null || h.waitStatus < 0 ||
(h = head) == null || h.waitStatus < 0) {
Node s = node.next;
if (s == null || s.isShared())
doReleaseShared();
}
}为什么这里两次判断h是否为空?什么时候h可以为null?我认为它们都不能为空。
发布于 2020-07-07 19:45:15
因为头节点是动态移动的,所以从两个方面调用doReleaseShared():
1.持有锁的线程调用release(),然后执行doReleaseShared()。
2.有人线程执行acquire(),preNode是头获取锁成功的锁,然后执行doReleaseShared();
考虑以下可能的执行顺序:
下面是一些节点:head->init node ->node1->node2
有人释放了锁,然后唤醒了node1,node1从unpark中恢复,(节点1的线程名为Thread1,节点2的线程名为Thread2...)Node1的preNode是head,获取成功,permit是一个点。
private void doAcquireSharedInterruptibly(int arg)
throws InterruptedException {
final Node node = addWaiter(Node.SHARED);
boolean failed = true;
try {
for (;;) {
final Node p = node.predecessor();
if (p == head) {
int r = tryAcquireShared(arg);//success , r=0;
if (r >= 0) { //true
setHeadAndPropagate(node, r);
p.next = null; // help GC
failed = false;
return;
}
}
if (shouldParkAfterFailedAcquire(p, node) &&
parkAndCheckInterrupt())
throw new InterruptedException();
}
} finally {
if (failed)
cancelAcquire(node);
}
}而在执行setHead(node)之后Thread1暂时挂起。
private void setHeadAndPropagate(Node node, int propagate) {
Node h = head; // Thread2 come here and the Thread1 execute continue
setHead(node);
//Note: this point,the setHead(node) is done,but time slice
// exhaustion,Thread1 is temporarily suspended
if (propagate > 0 || h == null || h.waitStatus < 0 ||
(h = head) == null || h.waitStatus < 0) {
Node s = node.next;
if (s == null || s.isShared())
doReleaseShared();
}
}另一个线程释放lock.current头是node1,CAS设置节点1的waitStatus==0,唤醒node2。
node2 preHead为node1并获取锁success.then execute setHeadAndPropagate()方法。
碰巧Node node = head和Thread2还在继续...
if (propagate > 0 || h == null || h.waitStatus < 0 ||
(h = head) == null || h.waitStatus < 0) {
Node s = node.next;
if (s == null || s.isShared())
doReleaseShared();
}
//return immediate ,because
//to old head
//propagate=0 false
//h==null fase
//h.waitStatus=0 false
//to new head node1
//propagate=0 false
//h==null fase
//h.waitStatus=0 false所以让我们回到过去
private void doAcquireSharedInterruptibly(int arg)
throws InterruptedException {
final Node node = addWaiter(Node.SHARED);
boolean failed = true;
try {
for (;;) {
final Node p = node.predecessor();
if (p == head) {
int r = tryAcquireShared(arg);
if (r >= 0) {
setHeadAndPropagate(node, r);
p.next = null; // help GC //node1 could be GC!!!
failed = false;
return;
}
}
if (shouldParkAfterFailedAcquire(p, node) &&
parkAndCheckInterrupt())
throw new InterruptedException();
}
} finally {
if (failed)
cancelAcquire(node);
}
}最后,我们回到Thread2,Thread2继续。
当node2判断setHeadAndPropagate()方法行990中的if(...)时。
可能会发生h==null。所以doReleaseShared()
摘要:作为您的请求,第一个h表示旧的头部,它可以是null(特殊情况,时间切片导致的线程调度),但随后的(h=head==null)不能是null,因为它是当前的Thread2,这意味着当前的alive.you可以将其视为常规检查,请不要介意。
发布于 2020-07-07 15:43:52
第一次检查head (Node h = head),下次检查-可能是node (setHead(node))。
https://stackoverflow.com/questions/62770269
复制相似问题