闽公网安备 35020302035485号
前言:
从前,有一对夫妻,男的叫牛郎,女的叫织女,他们很好地传承了中华民族的谦让美德,每次吃饭时都会优先考虑对方,如果对方饿的话,就让给对方吃,等对方吃饱了自己才吃,这种美德本身是好的,但是如果一味的谦让,就有可能都吃不上饭。因为这是典型的活锁问题。
活锁(Live Lock)是一个相对较新的概念,它指的是一种线程调度方式,在该方式下,线程会因为某些条件无法满足而一直处于等待状态,并不会阻塞或休眠。这种状态类似于“死锁”,但是与死锁不同的是,活锁是一种可恢复的锁,在一定条件下可以自行解开。
活锁通常发生在一个线程需要获取多个锁时。如果一个线程在获取某个锁时,发现该锁已经被其他线程持有,此时它可以选择等待一段时间然后再次尝试获取该锁。但是如果该线程始终无法获取到该锁,就会陷入等待状态,形成活锁。活锁的危害在于,它会使线程无法继续执行任务,占用系统资源,进而影响系统性能。因此,在编写多线程程序时,需要特别注意避免活锁的发生。
4.定义一个勺子类,有勺子表示就能够吃饭,里面有个属性表示所属人owner
publicclass LiveLock {
// 堆代码 duidaima.com
public static void main(String[] args) {
Diner husband = new Diner("牛郎");
Diner wife = new Diner("织女");
Spoon spoon = new Spoon(husband);
new Thread(new Runnable() {
@Override
public void run() {
husband.eatWith(spoon, wife);
}
}).start();
new Thread(new Runnable() {
@Override
public void run() {
wife.eatWith(spoon, husband);
}
}).start();
}
}
(2) 定义就餐者 Diner 类staticclass Diner {
/**
* 吃饭的人
*/
private String name;
/**
* 是否饥饿
*/
privateboolean 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;
}
}
(3) 定义行为方法eatWith()/**
* 方法里面描述的是吃饭的事
* 堆代码 duidaima.com
* @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);
}
}
(4) 定义一个勺子类staticclass Spoon {
/** 所属人owner **/
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.name);
}
}
三. 代码运行结果publicclass LiveLock {
public static void main(String[] args) {
Diner husband = new Diner("牛郎");
Diner wife = new Diner("织女");
Spoon spoon = new Spoon(husband);
new Thread(new Runnable() {
@Override
public void run() {
husband.eatWith(spoon, wife);
}
}).start();
new Thread(new Runnable() {
@Override
public void run() {
wife.eatWith(spoon, husband);
}
}).start();
}
staticclass Diner {
/**
* 吃饭的人
*/
private String name;
/**
* 是否饥饿
*/
privateboolean 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;
}
//先检查对方是否饥饿,如果对方饥饿的话先把勺子交给对方,让对方先吃
if (spouse.isHungry) {
System.out.println(name + ": 亲爱的" + spouse.name + "你先吃吧");
spoon.setOwner(spouse);
continue;
}
//开始使用勺子吃饭
spoon.use();
//吃完后把自己的状态改成非饥饿状态
isHungry = false;
System.out.println(name + ": 我吃完了");
//同时把勺子直接给到对方
spoon.setOwner(spouse);
}
}
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;
}
}
staticclass Spoon {
/** 所属人owner **/
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.name);
}
}
}
打印结果:
处理方案:加入随机因素,允许某些时候不谦让
/**
* 方法里面描述的是吃饭的事
* 堆代码 duidaima.com
* @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();
//先检查对方是否饥饿,如果对方饥饿的话先把勺子交给对方,让对方先吃,random.nextInt(10) < 9 表示有十分之一的概率不谦让
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);
}
}
打印结果:
可以看到他们在谦让了多次之后,织女终于吃到饭了,吃饱了之后勺子给了牛郎,牛郎也吃完了,然后就过上了没羞没臊的幸福生活…
总结:
活锁是一种需要特别注意的线程调度问题,它会影响程序的性能和稳定性。因此,在编写多线程程序时,我们需要采取一些措施来避免活锁的发生,以确保程序的正确性和可靠性。