Search code examples
javalambdajava-8jvmjvm-crash

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


PS: Sorry for my poor english.I can't describe the problem clearly. :(

When I don't use the "lambda method reference" code style in the static block, like:

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

then the program running forever, never stop.

But when I change the code to

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

then the bug gone.The program can finish immediately.

Just look directly at the code please, I already tried to simplify the code as far as I can.

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();
    }
}

enter image description here

but when I change the lambda code

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

to

System.out::println

the program finish immediately

enter image description here

Or I change parallelStream() to normal stream(),Bugs gone.

Or I remove the static blocks,Bugs gone too.

My jdk version is 1.8.0_202

And the OS version is MacOS 10.14.5


Solution

  • Interesting Question: This question is similar with Class Loading with Static Block Competition Cause Deadlock,

    but for this issue, it's caused by when use e -> {System.out.println(e);} after compiling, it will generate an synthetic method: anonymous static private method for this, as:

      // access flags 0x100A
      private static synthetic lambda$init$0(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
    

    this synthetic method: private static method is generated by e -> {System.out.println(e);} compile.

    also it's similar equal to:

    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);
    }
    

    so as Class Loading with Static Block Competition Cause Deadlock this post explanation: when init class BugSimulate, it will invoke static block firstly, but since it's using parallelStream and try to invoke the generated private anonymous method, this caused an competition with class initializer, so finally it's deadlock.

    Competition