我的代码中遇到了死锁情况。我使用以下测试代码重现了该场景(也请查看行号注释)。
我有一个ExecuterService
需要3个任务,2个任务在同一个对象上有一个同步块,没有初始化它应该有null
值。
synchronized(null){}
,所以我期待line-2
出错。但是,这是以死锁执行的。即前三个任务在第三个任务中等待。 (见输出-1)
现在如果我将line-1
更改为Object lock = new Object();
代码将完美运行而不会出现任何死锁(输出-2)。我只是想知道当我们提供未初始化的互斥对象时JVM到底发生了什么?看起来JVM正在为它创建一个静态副本,它由所有任务共享。因此死锁
public class Test {
Object lock; //line -1
Integer a = 10;
public static void main(String[] arg) {
new Test().doIt();
}
public void doIt() {
ExecutorService service = Executors.newFixedThreadPool(3);
service.submit(new Runnable() {
public void run() {
synchronized (Test.this.lock) { //line -2
try {
Thread.sleep(1000 * 5);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
Test.this.a = (int) Thread.currentThread().getId();
System.out.println(a + " " + Thread.currentThread().getId());
}
}
});
service.submit(new Runnable() {
public void run() {
synchronized (Test.this.lock) {
try {
Thread.sleep(1000 * 5);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
Test.this.a = (int) Thread.currentThread().getId();
System.out.println(a + " " + Thread.currentThread().getId());
}
}
}
);
service.submit(new Runnable() {
public void run() {
Test.this.a = (int) Thread.currentThread().getId();
while (true) {
try {
Thread.sleep(1 * 1000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println(a + " Main");
}
}
});
}
}
输出-1
11 Main
11 Main
11 Main
11 Main
11 Main
11 Main
11 Main
11 Main
11 Main
11 Main
11 Main
.
.
.
输出-2
11 Main
11 Main
11 Main
11 Main
9 9
9 Main
9 Main
9 Main
9 Main
9 Main
10 10
10 Main
10 Main
.
.
.
答案 0 :(得分:7)
您没有死锁 - 正如您预期的那样出现错误。第一个和第二个任务将抛出NullPointerException
,只留下第三个任务。
如果您在run()
/ try
声明中包围catch
的正文,则可以看到此内容。
答案 1 :(得分:3)
异常会在执行程序线程上抛出,除非您捕获或查询它,否则不可见。例如,你可以写:
Future<?> f = service.submit(new Runnable() { ... }
在主要结尾处:
try {
f.get();
} catch (ExecutionException | InterruptedException e) {
e.printStackTrace();
}
那会告诉你NPE。