2014-10-29 89 views
2

请参考下面的代码为什么它不会造成死锁?

package com.test; 

public class DeadLock { 

    private void method1() { 

     synchronized (Integer.class) { 
      method2(); 
     } 
    } 

    private void method2() { 
     synchronized (Integer.class) { 
      System.out.println("hi there"); 
     } 
    } 

    public static void main(String[] args) { 
     new DeadLock().method1(); 
    } 
} 

按我的理解,在method2代码不应该在任何情况下执行,因为method1持有Integer.classmethod2尝试锁再次访问Integer.class锁。但令我惊讶的是,代码运行良好,它向控制台输出“hi there”。有人可以澄清吗?

+1

互动(递归)互斥?在这种情况下,互斥锁可以从同一个线程获取多倍的时间,但会从多个线程中(死锁)锁定 – 2014-10-29 11:11:59

+0

为什么你认为它应该死锁?它直截了当的不是吗? – SMA 2014-10-29 11:13:33

+0

如果您只有一个线程,则无法获取锁定。 – Leonidos 2014-10-29 11:17:23

回答

4

锁由线程所有。如果你的线程已经拥有一个锁,那么Java假定你不需要再次获取它并继续。

,如果你在method1()开始线程在占用锁和第二个线程执行方法method2()你会得到一个僵局。

如果你喜欢的代码,然后​​是这样的:

Lock lock = Integer.class.getLock(); 
boolean acquired = false; 
try { 
    if(lock.owner != Thread.currentThread()) { 
     lock.acquire(); 
     acquired = true; 
    } 

    ...code inside of synchronized block... 
} finally { 
    if(acquired) lock.release(); 
} 

这里是代码演示了僵局。只需设置runInThreadtrue

package com.test; 

public class DeadLock { 

    private void method1() { 

     synchronized (Integer.class) { 
      boolean runInThread = false; 

      if(runInThread) { 
       Thread t = new Thread() { 
        @Override 
        public void run() { 
         method2(); 
        } 
       }; 
       t.start(); 
       try { 
        t.join(); // this never returns 
       } catch(InterruptedException e) { 
        e.printStackTrace(); 
       } 
      } else { 
       method2(); 
      } 
     } 
    } 

    private void method2() { 
     System.out.println("trying to lock"); 
     synchronized (Integer.class) { 
      System.out.println("hi there"); 
     } 
    } 

    public static void main(String[] args) { 
     new DeadLock().method1(); 
    } 
} 
+0

嗯,我怀疑它。实际上我想说的是,如果method1()获取自身的锁定,那么所有其他线程将处于等待状态na? – Krishna 2014-10-29 11:20:09

+0

对于像我这样的新鲜人来说,它的一点点沉重的解释:D哈哈反正+1正确答案。 – Krishna 2014-10-29 11:27:21

+0

无论多少个线程调用method1(),都不会有死锁。为了发生死锁,程序必须至少有两个锁。当某些线程集的每个成员持有一个锁并且阻止等待获取由其中一个成员持有的锁时发生死锁。在最简单的情况下,线程1持有锁A,并在尝试获取锁B时被阻塞。同时,线程2阻止了锁B,尝试获取锁A时线程2被锁定。在这种情况下,两个线程都无法做到任何进展。 – 2014-10-29 17:29:21

0

你的代码就相当于:

synchronized (Integer.class) { 
    synchronized (Integer.class) { 
     System.out.println("hi there"); 
    } 
} 

如果线程获取锁,进入第一​​块它不会有任何问题访问第二

为了产生死锁,对method2的调用应该由不同的线程执行。

+0

您不能仅使用一个锁对象创建死锁。看到我对Aaron Digulla的回答的评论。 – 2014-10-29 17:40:11

3

看来你误解了这个概念。 方法永远不会获取锁,在同步方法的情况下,调用该方法的实例用作锁,并且在同步块的情况下线程获取指定对象上的锁。

这里实例获取Integer.class上的锁,然后继续执行method2。

不存在死锁情况,因为在您的情况下线程继续执行您在method1内调用的方法。所以没有发生死锁。

+1

+1其正确:) – Krishna 2014-10-29 11:26:37

+1

@克里希纳感谢您的编辑和upvote。 – EMM 2014-10-29 11:28:31

+0

实例不获取lock.Lock将被执行它的线程获取。 – aniugne 2014-10-29 11:45:02

0
synchronized (Integer.class) { 
      method2(); 
     } 
当你调用这个 method2();那么它不给锁定任何种类的

mehtod其继续去您调用手段这个方法。

private void method2() { 
     synchronized (Integer.class) { 
      System.out.println("hi there"); 
     } 
    } 

并完成其返回。所以没有死锁的情况。希望这个解释有帮助。

0

如前所述,当没有其他线程已经阻止它时,一个线程可以访问多个同步块。在这种情况下,同一个线程可以重新输入同步块,因为它已经从method1中保持它。

为了导致死锁,您必须至少使用两个线程和两个不同的锁。它必须以相反的顺序访问两个锁。看看代码:

private void method1() throws InterruptedException 
{ 
    synchronized (Integer.class) 
    { 
     System.out.println(Thread.currentThread().getName() + " hi there method 1"); 
     Thread.sleep(1000); 
     method2(); 
    } 
} 

private void method2() throws InterruptedException 
{ 
    synchronized (Double.class) 
    { 
     System.out.println(Thread.currentThread().getName() + " hi there method 2"); 
     Thread.sleep(1000); 
     method1(); 
    } 
} 

public static void main(String[] args) throws InterruptedException 
{ 
    new Thread() 
    { 
     @Override 
     public void run() 
     { 
      try 
      { 
       new DeadLock().method1(); 
      } 
      catch (InterruptedException e) 
      { 
       e.printStackTrace(); 
      } 
     } 
    }.start(); 
    new DeadLock().method2(); 
} 
+1

我认为这个解决方案必须非常简短,并且很容易理解。 – Krishna 2014-10-29 11:31:13

+1

当你使用java的线程时,解决方案永远不会这样。但我已经掌握了,所以下次会尽我所能。 – 2014-10-29 12:03:52

+0

好祝你好运。 – Krishna 2014-10-29 12:34:59