从前,有一对非常恩爱的夫妻,他们都有一颗谦让的心,但家境却不是很好,吃了上顿没下顿,于是,当他们有食物的时候,他们会优先考虑对方,如果对方饿的话,就让给对方吃,等对方吃饱了自己才吃,这种美德本身是好的,但是如果一味的谦让,也会发生一些让人啼笑皆非的事儿…
案例演示
- 首先定义一个就餐者
Diner
,有两个属性,一个是名称name,一个是是否饥饿isHungry
- 就餐者有个行为方法
eatWith()
,他需要两个参数,一个是勺子,一个是夫妻对方,方法里面描述的是吃饭的事宜。
public class Diner {
/**
* 吃饭的人
*/
private String name;
/**
* 是否饥饿
*/
private boolean isHungry;
public Diner(String name) {
this.name = name;
isHungry = true;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public boolean isHungry() {
return isHungry;
}
public void setHungry(boolean hungry) {
isHungry = hungry;
}
/**
* 方法里面描述的是吃饭的事
*
* @param spoon 勺子
* @param spouse 夫妻对方
*/
public void eatWith(Spoon spoon, Diner spouse) {
while (isHungry) {
//如果勺子不是自己的,则等一会儿,等对方吃完
if (spoon.getOwner() != this) {
try {
Thread.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
continue;
}
//先检查对方是否饥饿,如果对方饥饿的话先把勺子交给对方,让对方先吃
if (spouse.isHungry) {
System.out.println(name + ": 亲爱的" + spouse.name + "你先吃吧");
spoon.setOwner(spouse);
continue;
}
//开始使用勺子吃饭
spoon.use();
//吃完后把自己的状态改成非饥饿状态
isHungry = false;
System.out.println(name + ": 我吃完了");
//同时把勺子直接给到对方
spoon.setOwner(spouse);
}
}
}
- 定义一个勺子类,有勺子表示就能够吃饭,里面有个属性表示所属人
owner
public class Spoon {
private Diner owner;
public Spoon(Diner owner) {
this.owner = owner;
}
public Diner getOwner() {
return owner;
}
public void setOwner(Diner owner) {
this.owner = owner;
}
public synchronized void use() {
System.out.printf("%s吃完了!", owner.getName());
}
}
- 定义主函数,主函数定义两个就餐者,一个是牛郎,一个就是织女了
public class LiveLock {
public static void main(String[] args) {
Diner husband = new Diner("牛郎");
Diner wife = new Diner("织女");
Spoon spoon = new Spoon(husband);
new Thread(() -> husband.eatWith(spoon, wife)).start();
new Thread(() -> wife.eatWith(spoon, husband)).start();
}
}
- 启动程序,看看打印结果:
我们可以看到,程序不停的说话:
…
牛郎: 亲爱的织女你先吃吧
织女: 亲爱的牛郎你先吃吧
…
一直重复让对方先吃,这就陷入了活锁的状态,因为程序并没有停下,还在不停打印输出,而且也没有完成吃饭的动作。
出现原因
其实主要问题出现在 if (spouse.isHungry)
这一句上,只要检测到对方是饥饿的话就始终谦让!
- 原因:
重试机制不变
,吃饭始终谦让 - 以太网的指数退避算法:连接重试时间不是固定的,而是
随机的
,并且随机范围随着碰撞强度的升高而逐渐扩大 - 处理方案:加入
随机因素
,不再是始终谦让
解决活锁问题
- 我们只要在
if (spouse.isHungry)
这一句的判断条件加一个随机因素即可
/**
* 方法里面描述的是吃饭的事
*
* @param spoon 勺子
* @param spouse 夫妻对方
*/
public void eatWith(Spoon spoon, Diner spouse) {
while (isHungry) {
//如果勺子不是自己的,则等一会儿,等对方吃完
if (spoon.getOwner() != this) {
try {
Thread.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
continue;
}
Random random = new Random();
//先检查对方是否饥饿,如果对方饥饿的话先把勺子交给对方,让对方先吃
if (spouse.isHungry && random.nextInt(10) < 9) {
System.out.println(name + ": 亲爱的" + spouse.name + "你先吃吧");
spoon.setOwner(spouse);
continue;
}
//开始使用勺子吃饭
spoon.use();
//吃完后把自己的状态改成非饥饿状态
isHungry = false;
System.out.println(name + ": 我吃完了");
//同时把勺子直接给到对方
spoon.setOwner(spouse);
}
}
- 看看打印结果:
可以看到他们在谦让了多次之后,牛郎终于吃到饭了,吃饱了之后勺子给了织女,织女也吃完了,然后就过上了没羞没臊的幸福生活…
(到此为止,完结撒花!)
想了解更多关于死锁相关的知识,请点击这里
笔记来源:慕课网悟空老师视频《Java并发核心知识体系精讲》