- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
最近我在学习并发。当我对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
两次是否为null? h
什么时候可以为空?我认为它们都不能为空。
最佳答案
因为头节点是动态移动的,调用 doReleaseShared()
来自两个方面:
1.持有锁的线程调用release()
然后执行doReleaseShared()
。
2.someone Thread执行acquire()
,preNode为head获取锁成功获取锁后执行doReleaseShared()
;
考虑以下可能的执行顺序:
这是一些节点:head--->init node--->node1--->node2
有人释放锁然后唤醒node1,node1从unpark中恢复,(node1的Thread named Thread1,node2的Thread named Thread2 ...)node1的preNode为head,获取成功,此时permit为1。
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);
}
}
而 Thread1 在执行 setHead(node)
后暂时挂起。
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();
}
}
另一个Thread释放锁,当前head为node1,CAS设置node1的waitStatus==0,唤醒node2。
node2 preHead为node1,获取锁成功,然后执行setHeadAndPropagate()
方法。
碰巧节点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表示旧的head,它可以是null
(特殊场景,时间分片引起的线程调度),但是后面的(h=head==null)
不能为null
,因为它是当前的Thread2,表示当前还活着。你可以把它当作例行检查,不要介意。
关于java - 为什么 `h`这个参数在AbstractQueuedSynchronizer中会判断两次是否为null?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/62770269/
聊聊JUC包下的底层支撑类-AbstractQueuedSynchronizer(AQS) juc包下的一堆并发工具类是我们日常开发特别是面试中常被拿来问的八股文之一,为了工作也好,为了面试也
在await AQS的方法(AbstractQueuedSynchronizer):我想知道 while (!isOnSyncQueue(node)) { 中 while 的含义 我觉得如果这个节点正
我正在查看 java.uti.concurrent.locks.AbstractQueuedSynchronizer 的源代码,acquire() 方法看起来像这样 - public final v
关闭。这个问题需要多问focused 。目前不接受答案。 想要改进此问题吗?更新问题,使其仅关注一个问题 editing this post . 已关闭 9 年前。 Improve this ques
我正在实现一个自定义的 FutureTask (未扩展)以在线程池等中使用。我需要特殊功能,并且无法直接扩展 FutureTask 的方法。为了帮助我做到这一点,我查看了默认实现。如果您无法访问代码,
我编写了一个使用 AbstractQueuedSynchronizer 的简单类。我写了一个代表“门”的类,如果打开则可以通过,如果关闭则阻塞。这是代码: public class GateBlock
大佬们,谁能给个LockSupport & AbstractQueuedSynchronizer的简单实用例子? javadocs 中给出的示例很紧张。 我理解 Semaphore 许可的使用。 感谢
我知道一些关于 AbstractQueuedSynchronizer 的细节。它是一个用于创建状态依赖类或同步器的框架。但是我没有得到在 ThreadPoolExecutor 的 Worker 中扩展
我试图从较高的层次理解 java 的并发 API 是如何使用 AbstractQueuedSynchronizer 作为构建 block 构建的。我在这个类中没有看到任何synchronized、wa
我无法弄清楚为什么几个“ajp-nio-8009-exec-XX”类型的线程被阻止。典型的线程转储堆栈跟踪如下所示: at sun.misc.Unsafe.park(Native Method)
我是一名优秀的程序员,十分优秀!