注意:这不是一个重复的问题,请仔细阅读主题 https://stackoverflow.com/users/3448419/apangin 引用:
真正的问题是,为什么代码有时候会在不应该的情况下起作用。 即使没有lambda表达式,问题也能够重现。这让我觉得可能存在JVM漏洞。
在https://stackoverflow.com/a/53709217/2674303的评论中,我试图找出代码的行为从一次启动到另一次启动的不同原因,并且讨论的参与者给了我一个建议,创建一个单独的主题。
我们来看一下以下源代码:
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
你能解释一下那个行为吗?
System.out.println("Finished");
移动到static {}
块的末尾时,我们可以清楚地显示工作线程成功执行了lambda主体,而类初始化尚未完成,即这不是流操作过早返回的问题。请注意,该示例对于较新版本的Java来说有些不幸,因为从Java 9开始,count()
将跳过整个处理并返回可预测的大小。因此,.map(i -> { System.out.println("map: "+Thread.currentThread().getName()+" "+i); return 1; }).sum();
可能更好。 - Holgergetstatic
/putstatic
字节码,但没有修复invokestatic
。 - apangin