多线程解决哲学家就餐问题(Java)
哲学家就餐问题是计算机科学中的一个经典问题,用于演示在并行计算中多线程同步时产生的问题。
题目要求:
五位哲学家围着一张桌子而坐,他们不交谈,每人面前放了一碗饭,每个人之间放了一只筷子(总共5只筷子)。哲学家只能做两件事, 吃饭和思考,吃饭时不思考,思考时不吃饭。哲学家只能拿起自己身边的两只筷子才能吃饭,拿筷子的顺序是先拿左手再拿右手(不同时)。
题目分析:
因为哲学家之间不会交谈故可能会发生很严重的情况:
1.发生死锁,即每个哲学家都是左手拿着筷子,等待着右侧的筷子空闲,这就发生了死锁,谁也吃不了饭。
2.出现他们同时左手拿起筷子,又同时放下左手的筷子,循环往复。
3.不加锁则会出现五个人同时吃饭的情况。
解题流程:
首先判断左右手是否同时有空闲的筷子,如果没有,就持续思考,如果有,则先取左手筷子再取右手筷子,然后停止思考并吃饭,吃完饭后清洗筷子放到桌面上并继续思考,此时处于吃饱状态,不会再重复吃饭。
public class Test {
public static void main(String[] args) {
Object obj = new Object();
boolean[] chopsticks= {false,false,false,false,false};//每位哲学家的筷子初始状态
for (int i = 0; i<5; i++) {
//创建线程
Philosophy phi = new Philosophy(i, false, false, true, true);
phi.setObj(obj);//带锁
phi.setChopsticks(chopsticks);//传筷子
phi.start();//启动线程
}
}
}
class Philosophy extends Thread{
//筷子状态
boolean[] chopsticks; //true 拿起 false 放下
//哲学家编号
private int i;
//左手
private Boolean leftFlag = false;//true 拿起 false 放下
//右手
private Boolean rightFlag = false;//true 拿起 false 放下
//饥饿状态
private Boolean hungry = true;//true 饥饿 false 已经吃完饭
//思考状态
private Boolean thinkFlag = false;//true 思考中 false 未思考
private Object obj;//锁
//有参构造
public Philosophy(int i, Boolean leftFlag, Boolean rightFlag, Boolean hungry,
Boolean thinkFlag) {
this.i = i;
this.leftFlag = leftFlag;
this.rightFlag = rightFlag;
this.hungry = hungry;
this.thinkFlag = thinkFlag;
}
//吃饭
public void eat() {
synchronized (obj) {
//当前哲学家的左右筷子都空闲 并且是饥饿状态 可以拿筷子
if(!chopsticks[this.i]&&!chopsticks[(this.i+1)%5]&&
!this.leftFlag&&!this.rightFlag&&this.hungry) {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
chopsticks[(this.i+1)%5] = true; //筷子被拿起
this.leftFlag=true;//左手有筷子
System.out.println("哲学家"+this.i+"拿起了左边的筷子");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
chopsticks[this.i] = true; //筷子被拿起
this.rightFlag=true;//右手有筷子
System.out.println("哲学家"+this.i+"拿起了右边的筷子");
}
}
if(this.leftFlag&&this.rightFlag&&this.hungry) {//满足条件 开始吃饭
System.out.println("哲学家"+this.i+"开始吃饭");
this.thinkFlag=false;//停止思考
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("哲学家"+this.i+"吃完饭了");
this.hungry=false;//不饿
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("哲学家"+this.i+"洗净并放下了筷子");
System.out.println("哲学家"+this.i+"开始思考");
this.thinkFlag=true;//思考
this.leftFlag=false;//左手放下筷子
this.rightFlag=false;//右手放下筷子
chopsticks[i] = false;
chopsticks[(i+1)%5] = false;
}
}
//思考
public void think() {
if(!this.leftFlag&&!this.rightFlag&&!this.thinkFlag) {
thinkFlag = true;
System.out.println("哲学家"+i+"开始思考");
}
}
//线程方法
@Override
public void run() {
while(true) {//循环判断每位哲学家的状态以及筷子的状态
this.eat();
this.think();
}
}
//设置筷子状态
public void setChopsticks(boolean[] chopsticks) {
this.chopsticks = chopsticks;
}
//设置锁对象
public void setObj(Object obj) {
this.obj = obj;
}
}
运行结果: