哲学家就餐问题
死锁发生的原因:由于0号哲学家申请了左边的0号叉子,还没来得及申请到右边的1号叉子,结果1号哲学家又把左边的1号叉子抢了过去,以此类推,,,,4号哲学家申请了左边的4号叉子,又转去申请0号叉子,结果是五个哲学家都同时拿起了左叉子而拿不到右叉子,最终进入了死循环从而导致了死锁现象。为了防止这种情况发的发生,我们可以有以下两种解决方案:
解决方案一:定义一个信号量,让每次只允许最多四个哲学家吃饭,这样就肯定有一个哲学家可以吃到饭,不会发生死锁现象。
解决方案二:我们发现,前四个哲学家同时从小到大的顺序申请叉子,那么如果4号哲学家也和前面的哲学家一样,都是从小到大去申请叉子,也就是如果他先申请0号叉子,再去申请4号叉子,那么问题不就解决了吗。因此,我们就可以限制哲学家们申请叉子的顺序来解决死锁问题。
具体的实现代码如下:注释的部分是通过信号量解决的,未注释的是通过限制顺序实现的;
package Data;
import java.util.concurrent.Semaphore;
public class PhilosopherProblem {
//public static final Semaphore MUTEX = new Semaphore(4); //定义一个互斥信号量(只允许四个哲学家吃饭)
public static void main(String[] args) {
Fork forks = new Fork();
Philosoper p0 = new Philosoper(forks,0);
Philosoper p1 = new Philosoper(forks,1);
Philosoper p2 = new Philosoper(forks,2);
Philosoper p3 = new Philosoper(forks,3);
Philosoper p4 = new Philosoper(forks,4);
p0.start();
p1.start();
p2.start();
p3.start();
p4.start();
}
}
class Fork{
private Semaphore[] forks = new Semaphore[] {
new Semaphore(1),new Semaphore(1),new Semaphore(1),new Semaphore(1),new Semaphore(1)};
//拿起叉子的方法
public void get(int fork_no){
try {
forks[fork_no].acquire();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
//放下叉子的方法
public void put(int fork_no) {
forks[fork_no].release();
}
//获取叉子的数量
public int getForkCount() {
return forks.length;
}
}
class Philosoper extends Thread{
private int no;
private Fork forks;
public Philosoper(Fork forks, int no) {
this.no = no;
this.forks = forks;
}
public void run() {
while(true) {
//(1)思考问题
System.out.println("哲学家"+no+"正在思考问题...");
//吃饭
int left = no;
int right = (no+1)%forks.getForkCount();
//如果右叉子编号大于左叉子编号,交换顺序
if(right > left) {
int temp = left;
left = right;
right = temp;
}
/*
* try { PhilosopherProblem.MUTEX.acquire(); } catch (InterruptedException e) {
* // TODO Auto-generated catch block e.printStackTrace(); }
*/
//1.拿起左叉子
forks.get(left);
System.out.println("\t\t\t哲学家"+no+"拿起左叉子");
//2.拿起右叉子
forks.get(right);
System.out.println("\t\t\t哲学家"+no+"拿起右叉子");
//3.吃饭
System.out.println("\t\t\t\t\t\t"+"哲学家"+no+"正在吃饭...");
//4.放下左叉子
forks.put(left);
System.out.println("\t\t\t哲学家"+no+"放下左叉子");
//5.放下右叉子
forks.put(right);
System.out.println("\t\t\t哲学家"+no+"放下右叉子");
//PhilosopherProblem.MUTEX.release();
}
}
}
配上测试结果图: