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();
}
}
but when I change the lambda code
e -> {System.out.println(e);}
to
System.out::println
the program finish immediately
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
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.