为什么在静态块中不使用"lambda method reference"代码风格会导致死锁?

Why when I don't use the "lambda method reference" code style in static block will cause deadlock?

PS:对不起我可怜的english.I没能把问题描述清楚。 :(

当我在静态块中不使用"lambda method reference"代码风格时,如:

static{
map.keySet().parallelStream().forEach(e -> {
            System.out.println(e);
        });
}

然后程序运行永远,永不停止。

但是当我将代码更改为

static{
map.keySet().parallelStream().forEach(System.out::println);
}

那么这个bug gone.The 程序可以立即完成。

请直接看代码,我已经尽量简化了代码。

public class BugSimulate {

    static {
        init();
    }

    private static void init() {
        Map<Integer, String> map = new HashMap<>();

        int i = 0;
        map.put(++i, "1");
        map.put(++i, "1");
        map.put(++i, "1");
        map.put(++i, "1");
        map.put(++i, "1");
        map.put(++i, "1");
        map.put(++i, "1");
        map.put(++i, "1");
        map.put(++i, "1");

        // running forever
        map.keySet().parallelStream().forEach(e -> {
            System.out.println(e);
        });

        // finish immediately
        //        map.keySet().parallelStream().forEach(System.out::println);
    }

    @Test
    public void test() {
        new BugSimulate();
    }
}

但是当我更改 lambda 代码时

e -> {System.out.println(e);}

System.out::println

程序立即完成

或者我将 parallelStream() 更改为普通的 stream(),错误消失了。

或者我删除了静态块,错误也消失了。

我的jdk版本是1.8。0_202

而OS版本是MacOS10.14.5

有趣的问题:这个问题与Class Loading with Static Block Competition Cause Deadlock

类似

但是这个问题是由于编译后使用e -> {System.out.println(e);}时,会生成一个合成方法:匿名静态私有方法为此,如:

  // access flags 0x100A
  private static synthetic lambda$init[=10=](Ljava/lang/Integer;)V
   L0
    LINENUMBER 27 L0
    GETSTATIC java/lang/System.out : Ljava/io/PrintStream;
    ALOAD 0
    INVOKEVIRTUAL java/io/PrintStream.println (Ljava/lang/Object;)V
   L1
    LINENUMBER 28 L1
    RETURN
   L2
    LOCALVARIABLE e Ljava/lang/Integer; L0 L2 0
    MAXSTACK = 2
    MAXLOCALS = 1

合成方法:私有静态方法e -> {System.out.println(e);}编译生成。

也类似于:

static {
    init();
}

private static void init() {
    Map<Integer, String> map = new HashMap<>();

    int i = 0;
    map.put(++i, "1");
    ***
    Thread foo = new Thread() {
        @Override
        public void run() {
            print(map.keySet().iterator().next()); //try access the private method, this cause a competition with **Class Initializer** and **static block**
        }
    };

    foo.start();
    try {
        foo.join();
    } catch (InterruptedException e) {
        e.printStackTrace();
    }
}
//equal to e -> {System.out.println(e);}
private static void print(int t) {
    System.out.println(t);
}

因此Class Loading with Static Block Competition Cause Deadlock这个post解释:当初始化classBugSimulate时,它会首先调用static block,但是因为它使用 parallelStream 并尝试调用生成的私有匿名方法,这导致了与 class 初始化程序 的竞争,所以最终陷入僵局.