哲学家就餐问题:有五个哲学家,他们的生活方式是交替地进行思考和进餐。他们共用一张圆桌,分别坐在五张椅子上。在圆桌上有五个碗和五支筷子,平时一个哲学家进行思考,饥饿时便试图取用其左、右最靠近他的筷子,只有在他拿到两支筷子时才能进餐。进餐完毕,放下筷子又继续思考。
场景:
因为每一个哲学家都只有吃饭或思考两种状态,只有同时拿起一双筷子时才能吃饭。我们把每一根筷子都看做是资源,两边的哲学家都看做是争抢资源的线程。
实体类筷子的代码如下
public class Chopstick {
private String name;
public Chopstick(String name) {
this.name = name;
}
public Chopstick() {
}
public String getName(){
return name;
}
public void setName(){
this.name = name;
}
@Override
public String toString() {
return "Chopstick{" +
"name='" + name + ''' +
'}';
}
}
哲学家的代码实现如下
/**
* @author 鞋头冠军
* @ClassName Philosopher
* @Date 2023/1/12
*/
public class Philosopher extends Thread{
private String name;
private Chopstick right;
private Chopstick left;
public Philosopher(String name, Chopstick right, Chopstick left){
this.name = name;
this.left = left;
this.right = right;
}
@Override
public void run() {
synchronized (left){
System.out.println(this.name+"拿起左手的"+this.left);
synchronized (right){
System.out.println(this.name+"拿起右手的"+this.right);
this.eat();
}
}
}
private void eat(){
System.out.println("吃饭中...");
long time = 1000;
try{
Thread.sleep(time);
}catch (InterruptedException e){
e.printStackTrace();
}
System.out.println(this.name+"吃完了");
}
}
测试类
public class Test {
public static void main(String[] args) {
Chopstick chopstick01 = new Chopstick("1号筷子");
Chopstick chopstick02 = new Chopstick("2号筷子");
Chopstick chopstick03 = new Chopstick("3号筷子");
Chopstick chopstick04 = new Chopstick("4号筷子");
Chopstick chopstick05 = new Chopstick("5号筷子");
Philosopher philosopher01 = new Philosopher("1号哲学家",chopstick05,chopstick01);
Philosopher philosopher02 = new Philosopher("2号哲学家",chopstick01,chopstick02);
Philosopher philosopher03 = new Philosopher("3号哲学家",chopstick02,chopstick03);
Philosopher philosopher04 = new Philosopher("4号哲学家",chopstick03,chopstick04);
Philosopher philosopher05 = new Philosopher("5号哲学家",chopstick04,chopstick05);
philosopher01.start();
philosopher02.start();
philosopher03.start();
philosopher04.start();
philosopher05.start();
}
}
测试结果1:当哲学家都在同一时刻拿起了自己左手边的筷子,则直接陷入死锁的状态
测试结果2:因为哲学家(线程)拿起筷子的速度不同,有的哲学家拿起速度快得到了一双筷子吃到了食物,吃完食物后放下。
解决方案:
当哲学家要吃饭的时候,要么同时拿起一双筷子,要么一只都不拿。
思路:我们可以通过创建一个boolean数组,对不同的筷子进行状态的赋值,当哲学家拿起某根筷子时,该筷子状态改变并不能被其他的哲学家拿起。当哲学家放下筷子时,通知所有的哲学家,并改变筷子为原来的状态。 通过分析代码实现如下:
Chopstick类
public class Chopstick {
private int name;
public Chopstick(int name) {
this.name = name;
}
public Chopstick() {
}
public int getName() {
return name;
}
public void setName(int name) {
this.name = name;
}
@Override
public String toString() {
return "Chopstick{" +
"name=" + name +
'}';
}
}
哲学家Philosopher类
/**
* @author 鞋头冠军
* @ClassName Philosopher
* @Date 2023/1/12
*/
public class Philosopher extends Thread{
private boolean[] take = new boolean[] {false, false, false, false, false};
private static String LOCK = "lock";
private String name;
private Chopstick chopstick;
public Philosopher(String name, Chopstick chopstick){
this.name = name;
this.chopstick = chopstick;
}
//拿起筷子被占用时就要放弃拿起,并释放锁
public void takeChopstick(){
synchronized (LOCK){
if (take[chopstick.getName()] || take[(chopstick.getName() + 1) % 5] ){
try{
LOCK.wait();
}catch (InterruptedException e){
e.printStackTrace();
}
}
take[chopstick.getName()] = true;
take[(chopstick.getName() + 1) % 5] = true;
}
}
//放下筷子的时候也要申请锁,并通知所有线程
public void putDownChopsticks() {
synchronized(LOCK) {
take[chopstick.getName()] = false;
take[(chopstick.getName() + 1) % 5] = false;
System.out.println(this.name + "号哲学家放下筷子"+chopstick);
LOCK.notifyAll();
}
}
@Override
public void run(){
while (true) {
takeChopstick();
eat();
putDownChopsticks();
}
}
private void eat(){
System.out.println("吃饭中...");
long time = 1000;
try{
Thread.sleep(time);
}catch (InterruptedException e){
e.printStackTrace();
}
System.out.println(this.name+"吃完了");
}
}
测试类Test
public class Test {
public static void main(String[] args) {
Chopstick chopstick01 = new Chopstick(1);
Chopstick chopstick02 = new Chopstick(2);
Chopstick chopstick03 = new Chopstick(3);
Chopstick chopstick04 = new Chopstick(4);
Chopstick chopstick05 = new Chopstick(5);
Philosopher philosopher01 = new Philosopher("1号哲学家",chopstick01);
Philosopher philosopher02 = new Philosopher("2号哲学家",chopstick02);
Philosopher philosopher03 = new Philosopher("3号哲学家",chopstick03);
Philosopher philosopher04 = new Philosopher("4号哲学家",chopstick04);
Philosopher philosopher05 = new Philosopher("5号哲学家",chopstick05);
philosopher01.start();
philosopher02.start();
philosopher03.start();
philosopher04.start();
philosopher05.start();
}
}
测试结果:
小结:
对于哲学家就餐问题除了上述还有多种解决方案,欢迎在评论区留言交流。如果本文对你有所帮助,可以给博主点个赞❤。