为什么在静态块中不使用"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 初始化程序 的竞争,所以最终陷入僵局.
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 初始化程序 的竞争,所以最终陷入僵局.