Java的:为什么这是一个死锁时锁定为空?

问题描述:

我有我的代码死锁情况。我使用以下测试代码复制了场景(也请看行号注释)。Java的:为什么这是一个死锁时锁定为空?

我有一个ExecuterService这需要3个任务,任务2具有在其上没有初始化它应具有null值相同对象的同步块。

synchronized(null){},所以我在line-2预期的错误Java不允许。但是,这会执行死锁。即前两个任务等待第三个任务。 (见输出-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 
. 
. 
. 

你没有一个僵局 - 但只是如你预期的错误。第一和第二个任务将抛出NullPointerException,只留下第三个任务运行。

如果在try/catch语句中围绕run()正文,则可以看到此内容。

+0

嗯知道了,该异常没有抓住并打印。得到它了。对我来说太愚蠢了...... –

+0

@MangatRaiModi:好吧,不幸的是它很沉默 - 这是一个问题的解决办法,国际海事组织。如果有一种简单的注册错误侦听器或其他方法会很好......你可以通过提交来检查返回的'Future',看看它是否完成,但不是错误......你可以通过调用'得到()'当然。 –

+0

非常感谢,unchecked异常总是疼。 –

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

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

,并在主要的结尾:

try { 
    f.get(); 
} catch (ExecutionException | InterruptedException e) { 
    e.printStackTrace(); 
} 

会告诉你的NPE。