相关疑难解决方法(0)

为什么在静态初始化程序中使用lambda的并行流导致死锁?

我遇到了一个奇怪的情况,在静态初始化程序中使用带有lambda的并行流看似永远没有CPU利用率.这是代码:

class Deadlock {
    static {
        IntStream.range(0, 10000).parallel().map(i -> i).count();
        System.out.println("done");
    }
    public static void main(final String[] args) {}
}
Run Code Online (Sandbox Code Playgroud)

这似乎是此行为的最小再现测试用例.如果我:

  • 将块放在main方法而不是静态初始化器中,
  • 删除并行化,或
  • 删除lambda,

代码立即完成.谁能解释这种行为?这是一个错误还是这个意图?

我正在使用OpenJDK版本1.8.0_66-internal.

java deadlock fork-join java-8 java-stream

82
推荐指数
3
解决办法
4222
查看次数

为什么在静态初始化器中使用并行流会导致不稳定的死锁

注意:这是不是重复,请仔细阅读题目сarefully /sf/users/241389361/报价:

真正的问题是为什么代码有时会起作用.即使没有lambdas,问题也会重现.这让我觉得可能存在JVM错误.

/sf/answers/3759645221/的评论中,我试图找出原因,为什么代码的行为从一个开始到另一个不同,并且该讨论的参与者给了我一些建议来创建一个单独的主题.

不要考虑以下源代码:

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");
    }
}
Run Code Online (Sandbox Code Playgroud)

有时(几乎总是)它会导致死锁.

输出示例:

static initializer: main
map: main 2
map: ForkJoinPool.commonPool-worker-3 4
map: ForkJoinPool.commonPool-worker-3 3
map: ForkJoinPool.commonPool-worker-2 0
Run Code Online (Sandbox Code Playgroud)

但有时它会成功完成(非常罕见):

static initializer: main
map: main 2
map: main …
Run Code Online (Sandbox Code Playgroud)

java concurrency deadlock jvm-hotspot static-initialization

18
推荐指数
1
解决办法
894
查看次数