多线程中的死锁示例
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
据我所知,流程是这样的:
- Thread1 进入 resource1 上的同步块并休眠
- 线程 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
的锁。
我认为您没有注意到的是,两个对象的锁都将在两个线程唤醒时获取。
在查看有关死锁的示例时,我遇到了这段代码:
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
据我所知,流程是这样的:
- Thread1 进入 resource1 上的同步块并休眠
- 线程 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
的锁。
我认为您没有注意到的是,两个对象的锁都将在两个线程唤醒时获取。