我是多线程的新手,我遇到了以下示例:
public class TestThread {
public static Object Lock1 = new Object();
public static Object Lock2 = new Object();
public static void main(String args[]) {
ThreadDemo1 T1 = new ThreadDemo1();
ThreadDemo2 T2 = new ThreadDemo2();
T1.start();
T2.start();
}
private static class ThreadDemo1 extends Thread {
public void run() {
synchronized (Lock1) {
System.out.println("Thread 1: Holding lock 1...");
try { Thread.sleep(10); }
catch (InterruptedException e) {}
System.out.println("Thread 1: Waiting for lock 2...");
synchronized (Lock2) {
System.out.println("Thread 1: Holding lock 1 & 2...");
}
}
}
}
private static class ThreadDemo2 extends Thread {
public void run() {
synchronized (Lock2) {
System.out.println("Thread 2: Holding lock 2...");
try { Thread.sleep(10); }
catch (InterruptedException e) {}
System.out.println("Thread 2: Waiting for lock 1...");
synchronized (Lock1) {
System.out.println("Thread 2: Holding lock 1 & 2...");
}
}
}
}
}
这将导致以下示例输出:
Thread 1: Holding lock 1...
Thread 2: Holding lock 2...
Thread 1: Waiting for lock 2...
Thread 2: Waiting for lock 1...
即存在僵局。但是,如果我们更改在第二个线程中获得的锁的顺序,以便现在看起来像这样:
public class TestThread {
public static Object Lock1 = new Object();
public static Object Lock2 = new Object();
public static void main(String args[]) {
ThreadDemo1 T1 = new ThreadDemo1();
ThreadDemo2 T2 = new ThreadDemo2();
T1.start();
T2.start();
}
private static class ThreadDemo1 extends Thread {
public void run() {
synchronized (Lock1) {
System.out.println("Thread 1: Holding lock 1...");
try { Thread.sleep(10); }
catch (InterruptedException e) {}
System.out.println("Thread 1: Waiting for lock 2...");
synchronized (Lock2) {
System.out.println("Thread 1: Holding lock 1 & 2...");
}
}
}
}
private static class ThreadDemo2 extends Thread {
public void run() {
synchronized (Lock1) {
System.out.println("Thread 2: Holding lock 1...");
try { Thread.sleep(10); }
catch (InterruptedException e) {}
System.out.println("Thread 2: Waiting for lock 2...");
synchronized (Lock2) {
System.out.println("Thread 2: Holding lock 1 & 2...");
}
}
}
}
}
它可以按预期工作,并且示例输出如下所示:
Thread 1: Holding lock 1...
Thread 1: Waiting for lock 2...
Thread 1: Holding lock 1 & 2...
Thread 2: Holding lock 1...
Thread 2: Waiting for lock 2...
Thread 2: Holding lock 1 & 2...
有人可以向我解释导致死锁的第一个事件是什么,为什么第二个代码的更改可以解决该问题?
最佳答案
这是第一种情况的可能方案:
线程1获取Lock1
并进入睡眠状态10毫秒。现在,线程2获取Lock2
并进入睡眠状态10毫秒。
现在,线程1尝试获取Lock2
,但由于它是由线程2获取的,所以无法获取它,而线程2试图获取被线程1锁定的Lock1
。
在第二种情况下,我们假设选择第一个线程来运行。它获取Lock1
,而另一个线程被阻止,因为它也尝试获取Lock1
。现在线程1进入睡眠状态,并进入第二个(嵌套的)同步块。它尝试获取它(因为它仍然是免费的)-现在他获得了 2个锁。另一个线程仍然被阻止。
仅在完成执行后,它才释放和两个锁(因为它退出了同步块),现在JVM可以自由决定选择哪个线程了,但这并不重要,发生相同的逻辑。