多线程中的死锁示例

Deadlock example in Multi threading

在查看有关死锁的示例时,我遇到了这段代码:

public class TestDeadlockExample1 {  
public static void main(String[] args) {  
final String resource1 = "ratan jaiswal";  
final String resource2 = "vimal jaiswal";  
// t1 tries to lock resource1 then resource2  
Thread t1 = new Thread() {  
  public void run() {  
      synchronized (resource1) {  
       System.out.println("Thread 1: locked resource 1");  

       try { Thread.sleep(100);} catch (Exception e) {}  

       synchronized (resource2) {  
        System.out.println("Thread 1: locked resource 2");  
       }  
     }  
  }  
};  

// t2 tries to lock resource2 then resource1  
Thread t2 = new Thread() {  
  public void run() {  
    synchronized (resource2) {  
      System.out.println("Thread 2: locked resource 2");  

      try { Thread.sleep(100);} catch (Exception e) {}  

      synchronized (resource1) {  
        System.out.println("Thread 2: locked resource 1");  
      }  
    }  
  }  
};  


t1.start();  
t2.start();  
}  
}  

输出:

Thread 1: locked resource 1

Thread 2: locked resource 2

Timeout due to heavy load

据我所知,流程是这样的:

  1. Thread1 进入 resource1 上的同步块并休眠
  2. 线程 2 进入资源 2 上的同步块并休眠

我的疑惑是,如果 Thread1 在 Thread2 之前恢复执行,因为它在 Thread2 之前休眠,那么为什么它没有在 resource2 进入同步块,因为那时 Thread2 必须离开同步块 resource2 并完全避免了死锁?同样疑惑的是为什么 Thread2 在 Thread1 离开之前的同一个块后 resource1 进入同步块?

问题是您设计的线程在您的系统中并不孤单,无法保证它们会在您调用 start() 后立即启动,也无法保证它们会保持同步的睡眠状态。这就是死锁进程的全部要点,因为系统不断在进程(进程的线程)之间切换,可能会出现这样一种情况,即一个进程需要一个正在被另一个进程使用的资源 process.You 永远不能假定进程中的时间限制,除非你设计一个更复杂的同步结构:/

正如其中一条评论所解释的那样,通常发生死锁的原因之一是一个进程在使用完资源后没有释放资源。嵌套同步块就是这种情况。

正如问题的评论部分所指出的,我错过了死锁的一个重要线索,即同步块彼此嵌套,因此直到整个父同步块完成对父同步块的锁定资源不会被释放。为了验证,我删除了嵌套的大括号并使块独立,似乎避免了死锁。请让我知道我的理解是否正确

考虑一下,Thread1 已经完成了这些指令

synchronized (resource1) {  
   System.out.println("Thread 1: locked resource 1");  

   try { Thread.sleep(100);} catch (Exception e) {}  

现在进入休眠状态,线程 2 在进入休眠状态之前完成以下指令。

synchronized (resource2) {  
  System.out.println("Thread 2: locked resource 2");  

  try { Thread.sleep(100);} catch (Exception e) {}  

现在当Thread1唤醒时,它会尝试执行

 synchronized (resource2) {  
    System.out.println("Thread 1: locked resource 2");  
   } 

但它无法完成它的执行,因为 Thread2 已经锁定 resource2。因为它是在 resource2 上同步的,所以它不会进一步执行,除非 Thread2 释放 resourse2 上的锁。这是等待的经典例子。

同样,当Thread2 唤醒时,它无法继续执行,因为它正在等待被thread1

锁定的Resource1

My doubt is that if Thread1 resumed execution before Thread2 since it slept before Thread2

记住multi-threading的第一条规则,如果你启动2个线程,不能保证哪个线程先启动,所以你不能确定你的线程1先启动休眠还是线程2先启动先开始睡觉。

then why didn't it enter the sync block on resource2since by that time Thread2 must have left the sync block on resource2 and avoided the Deadlock altogether ?

请注意,在两个线程中,您都在这样做:

  • 获取第一个对象的锁
  • 睡觉
  • 获得第二个对象的锁
  • 释放第二个对象的锁
  • 释放第一个对象的锁

所以,两个线程都会先获得锁然后休眠,并且 Thread2 在 Thread1 醒来时还没有获得 resource2 锁的可能性非常小,所以几乎每次你陷入僵局。

我认为这个例子是为了演示死锁。

"might"没有死锁如果:

  • 在 Thread2 中,您在 synchronized (resource2) { 之前有 try { Thread.sleep(100);} catch (Exception e) {}。因为有了这个,线程 1 有可能在线程 2 醒来时获得 resource2 的锁。

我认为您没有注意到的是,两个对象的锁都将在两个线程唤醒时获取。