【问题标题】:Why synchronized method cannot cause deadLock为什么同步方法不会导致死锁
【发布时间】:2020-10-18 07:27:28
【问题描述】:
我使用synchronized来测试deadLock,我发现synchronized不会通过在method上添加导致deadLock。代码如下:
public static void main(String[] args) {
DeadLock t1 = new DeadLock();
DeadLock t2 = new DeadLock();
new Thread(() -> {
t1.m1();
}).start();
new Thread(() -> {
t2.m1();
}).start();
}
synchronized void m1() {
System.out.println(Thread.currentThread().getName() + ":m1 start");
try {
TimeUnit.SECONDS.sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + ":m1 waiting to get m2");
m2();
}
synchronized void m2() {
System.out.println(Thread.currentThread().getName() + ":m2 start");
try {
TimeUnit.SECONDS.sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + ":m2 waiting to get m1");
m1();
}
为什么同步方法不会导致死锁,总是循环执行。
【问题讨论】:
标签:
java
deadlock
synchronized
【解决方案1】:
您在两个不同的实例上调用m1() 方法。 synchronized 关键字阻止从多个同步块/方法对相同对象的并发访问。 Read this
要导致死锁,两个线程应该请求另一个线程当前占用的资源。
此代码将成功陷入死锁!
public class DeadLock {
public static void main(String[] args) {
DeadLock t1 = new DeadLock();
DeadLock t2 = new DeadLock();
t1.setOther(t2);
t2.setOther(t1);
new Thread(() -> {
t1.m1();
}).start();
new Thread(() -> {
t2.m1();
}).start();
}
private DeadLock other;
public void setOther(DeadLock other) {
this.other = other;
}
void print(String msg) {
System.out.println(Thread.currentThread().getName() + msg);
}
synchronized void m1() {
print(":m1 start");
try {
TimeUnit.MILLISECONDS.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
print(":m1 waiting to get other.m1");
other.m1();
}
}
【解决方案2】:
发生这种情况是因为 Java 中的隐式对象监视器锁是可重入的。也就是说,如果一个线程持有一个对象上的隐式监视器锁,它将能够执行由该锁保护的任何代码。当一个线程进入m1()时,它可以进入m2()(反之亦然),因为它已经拥有了锁。这将无限期地发生
要演示死锁,您必须使用两种不同的锁来保护方法:
void m1() {
synchronized(obj1) {
System.out.println(Thread.currentThread().getName() + ":m1 start");
try {
TimeUnit.SECONDS.sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + ":m1 waiting to get m2");
m2();
}
}
void m2() {
synchronized(obj2) {
System.out.println(Thread.currentThread().getName() + ":m2 start");
try {
TimeUnit.SECONDS.sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + ":m2 waiting to get m1");
m1();
}
}
然后在相同DeadLock对象上调用这些方法。