前言:
从前,有一对夫妻,男的叫牛郎,女的叫织女,他们很好地传承了中华民族的谦让美德,每次吃饭时都会优先考虑对方,如果对方饿的话,就让给对方吃,等对方吃饱了自己才吃,这种美德本身是好的,但是如果一味的谦让,就有可能都吃不上饭。因为这是典型的活锁问题。
活锁(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); } }打印结果:
可以看到他们在谦让了多次之后,织女终于吃到饭了,吃饱了之后勺子给了牛郎,牛郎也吃完了,然后就过上了没羞没臊的幸福生活…
总结:
活锁是一种需要特别注意的线程调度问题,它会影响程序的性能和稳定性。因此,在编写多线程程序时,我们需要采取一些措施来避免活锁的发生,以确保程序的正确性和可靠性。