Java 如何防止同步方法中的死锁?

Java 如何防止同步方法中的死锁?,java,multithreading,methods,deadlock,synchronized,Java,Multithreading,Methods,Deadlock,Synchronized,在下面的代码中,可能会出现类似于问题“”的死锁,现在我明白了为什么这两个线程会出现死锁 死锁,但当我执行代码时,线程总是进入死锁,因此: 1-此代码中何时不可能出现死锁? 2-如何防止其发生 我尝试使用wait()和notifyAll()如下: wait() waver.waveBack(this) 然后在waveBack()中调用notifyAll(),但它不起作用,我遗漏了什么或误解了什么 包mainApp; 公共课浪潮{ 静态班友{ 私有最终字符串名; 公共好友(字符串名称){ thi

在下面的代码中,可能会出现类似于问题“”的死锁,现在我明白了为什么这两个线程会出现死锁 死锁,但当我执行代码时,线程总是进入死锁,因此:

1-此代码中何时不可能出现死锁?

2-如何防止其发生

我尝试使用wait()notifyAll()如下:

wait()
waver.waveBack(this)
然后在waveBack()中调用notifyAll(),但它不起作用,我遗漏了什么或误解了什么

包mainApp;
公共课浪潮{
静态班友{
私有最终字符串名;
公共好友(字符串名称){
this.name=名称;
}
公共字符串getName(){
返回此.name;
}
公共同步无效波(朋友波){
字符串tmpname=waver.getName();
System.out.printf(“%s:%s已向我挥手!%n”,this.name,tmpname);
动摇,动摇(这个);
}
公共同步无效回退(好友回退){
字符串tmpname=waver.getName();
System.out.printf(“%s:%s已向我挥手!%n”,this.name,tmpname);
}
}
公共静态void main(字符串[]args){
最终朋友friendA=新朋友(“friendA”);
最后的朋友friendB=新朋友(“friendB”);
新线程(newrunnable()){
公开募捐{
friendA.wave(friendB);
}
}).start();
新线程(newrunnable()){
公开募捐{
friendB.wave(friendA);
}
}).start();
}
}

在这种情况下,在持有锁时,不要调用可能需要锁的其他方法。这确保了总有一个时间点,方法可以获得锁并取得进展

在waver之前调用
wait()
。waveBack(this)会导致鸡和蛋的问题:
waveBack(this)
从未被调用,因为线程在
wait()
语句处停止执行,因此从未调用
notifyAll()
以继续执行

在本例的上下文中,有多种方法可以防止死锁,但是让我们来看看他对您链接的问题的评论中的
sarnold
中的建议。解释一下sarnold:“通常更容易对数据锁定进行推理”

让我们假设同步方法是同步的,以确保状态的一致更新(即,某些变量需要更新,但在任何给定时间只有一个线程可以修改这些变量)。例如,让我们注册发送和接收的波的数量。下面的可运行代码应说明这一点:

import java.util.HashMap;
导入java.util.List;
导入java.util.Map;
导入java.util.Random;
导入java.util.concurrent.ExecutorService;
导入java.util.concurrent.Executors;
导入java.util.concurrent.Future;
导入java.util.stream.collector;
导入java.util.stream.IntStream;
公共课浪潮{
静态类波{
final-Map-send=new-HashMap();
接收到的最终映射=新HashMap();
void addSend(朋友f){
添加(f,发送);
}
收到无效地址(朋友f){
添加(f,已收到);
}
空添加(朋友f,地图m){
m、 合并(f,1,(i,j)->i+j);
}
}
静态班友{
最后的字符串名;
公共好友(字符串名称){
this.name=名称;
}
最终波=新波();
虚波(朋友){
if(friend==这个){
return;//无法向self挥手。
}
同步(波){
waves.addSend(朋友);
}
waveBack(this);//在同步块之外以防止死锁
}
无效回退(朋友){
同步(波){
挥手致意(朋友);
}
}
字符串波(布尔发送){
同步(波){
Map m=(发送?waves.send:waves.received);
返回m.keySet().stream().map(f->f.name+”:“+m.get(f))
.sorted().collect(collector.toList()).toString();
}
}
@凌驾
公共字符串toString(){
返回名称+“:“+waves(true)+”/“+waves(false);
}
}
最终静态int maxThreads=4;
最终静态整数maxFriends=4;
最终静态int maxWaves=50_000;
公共静态void main(字符串[]args){
试一试{
List friends=IntStream.range(0,maxFriends)
.mapToObj(i->newfriend(“F_”+i)).collect(Collectors.toList());
ExecutorService executor=Executors.newFixedThreadPool(maxThreads);
随机=新随机();

ListAlways以相同的顺序获取锁。只有当您试图等待的某个特定条件受到您在等待时释放的锁的保护时,才可以使用
wait
。您可以调用
notifyAll
来提醒其他线程该条件可能已更改,但如果没有实际发生任何条件,则该命令没有任何作用y已被更改。
.wait()
notify()
是非常低级的工具,很难正确使用。请查看
信号灯中的任何工具是否有帮助;它们更易于使用。有效的Java第69项详细介绍了如何使用
wait()
notify()
安全。我对wait()和notifyAll()的理解有误。感谢您的澄清,尽管这是考试的一部分,我应该在保留程序语义的同时防止死锁,我不允许更改ma