【发布时间】:2018-12-11 12:56:39
【问题描述】:
注意:并非重复,请仔细阅读主题 https://stackoverflow.com/users/3448419/apangin报价:
真正的问题是为什么代码有时会在不应该运行的情况下运行。 即使没有 lambda,问题也会重现。这让我想到那里 可能是 JVM 错误。
在 https://stackoverflow.com/a/53709217/2674303 的 cmets 中,我试图找出代码行为从一个开始到另一个不同的原因,该讨论的参与者向我提出了创建单独主题的建议。
让我们考虑以下源代码:
public class Test {
static {
System.out.println("static initializer: " + Thread.currentThread().getName());
final long SUM = IntStream.range(0, 5)
.parallel()
.mapToObj(i -> {
System.out.println("map: " + Thread.currentThread().getName() + " " + i);
return i;
})
.sum();
}
public static void main(String[] args) {
System.out.println("Finished");
}
}
有时(几乎总是)会导致死锁。
输出示例:
static initializer: main
map: main 2
map: ForkJoinPool.commonPool-worker-3 4
map: ForkJoinPool.commonPool-worker-3 3
map: ForkJoinPool.commonPool-worker-2 0
但有时它会成功完成(非常罕见):
static initializer: main
map: main 2
map: main 3
map: ForkJoinPool.commonPool-worker-2 4
map: ForkJoinPool.commonPool-worker-1 1
map: ForkJoinPool.commonPool-worker-3 0
Finished
或
static initializer: main
map: main 2
map: ForkJoinPool.commonPool-worker-2 0
map: ForkJoinPool.commonPool-worker-1 1
map: ForkJoinPool.commonPool-worker-3 4
map: main 3
你能解释一下这种行为吗?
【问题讨论】:
-
在重复的问题中,not 到底解释了什么?答案归结为:“编写这样的代码会导致死锁。所以不要编写这样的代码”。您认为还可以添加什么?
-
多线程的本质是对时间敏感。如果它总是失败,或者永远不会失败,那么“多个线程”就不会难了。
-
所有可能的组合...可能适用于您的小示例,但考虑到任何实际的、现实的问题,您会迅速掠夺成倍增长的组合。而你唯一可以可能预测的就是出现僵局的可能性?
-
这不是重复的。真正的问题是为什么代码有时在它不应该工作的时候工作。即使没有 lambda,问题也会重现。这让我觉得可能存在 JVM 错误。稍后我会检查它。
-
是的,我现在确信这是一个显然与常量池解析有关的 JVM 错误。我还发现了一个关于静态字段访问的非常古老的类似错误JDK-4493560。似乎该错误已针对
getstatic/putstatic字节码修复,但不适用于invokestatic。
标签: java concurrency deadlock jvm-hotspot static-initialization