Java:当锁为null时,为什么会出现死锁?

Java:当锁为null时,为什么会出现死锁?,java,multithreading,Java,Multithreading,我的代码中有一个死锁场景。我用下面的测试代码重现了这个场景(也看看行号注释) 我有一个ExecuterService,它接受3个任务,2个任务在同一个对象上有一个未初始化的同步块。它应该具有null值 synchronized(null){}在java中是不允许的,所以我希望在第2行出现错误。但是,这是在死锁的情况下执行的。i、 e.前两个任务由第三个任务等待。(见产出-1) 现在,如果我将line-1更改为objectlock=newobject()代码将在没有任何死锁的情况下完美地工作(输出

我的代码中有一个死锁场景。我用下面的测试代码重现了这个场景(也看看行号注释)

我有一个
ExecuterService
,它接受3个任务,2个任务在同一个对象上有一个未初始化的同步块。它应该具有
null

synchronized(null){}
在java中是不允许的,所以我希望在
第2行出现错误。但是,这是在死锁的情况下执行的。i、 e.前两个任务由第三个任务等待。(见产出-1)

现在,如果我将
line-1
更改为
objectlock=newobject()代码将在没有任何死锁的情况下完美地工作(输出-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
.
.
.

您没有死锁-正如您预期的那样,出现了一个错误。第一个和第二个任务将抛出
NullPointerException
,只剩下第三个任务在运行


如果在
try
/
catch
语句中围绕
run()
的主体,您可以看到这一点。

异常在执行器线程上抛出,除非捕获或查询它,否则不可见。例如,你可以写:

Future<?> f = service.submit(new Runnable() { ... }

这将向您显示NPE。

啊,明白了,这个异常永远不会被捕获和打印。知道了。我真是太蠢了…@MangatRaiModi:嗯,不幸的是它太沉默了——这是一个问题的秘方,IMO。如果有一个简单的方法来注册一个错误监听器或什么的话,那就太好了。。。您可以检查submit返回的
Future
,查看它是否完成,但不检查错误。。。当然,您可以通过调用
get()
来实现这一点。非常感谢,未经检查的异常总是令人痛苦的。
try {
  f.get();
} catch (ExecutionException | InterruptedException e) {
  e.printStackTrace();
}