哲学家算法
操作系统中,为了避免互斥资源使用导致死锁 问题,有很多的解决方法,其中一种方法就是哲学家算法。
首先说一下什么是哲学家算法,有5个哲学家,他们只会思考和吃饭,但是在一个圆形的桌子上面 只有5支筷子,这些哲学家什么时候来吃东西是不确定的,也就是说,同一时间可能会有5个人来进食,也可能一个人也没有。 要想吃饭,必须有两双筷子,所以要约定一种取得筷子的方法。如果没有什么约束条件,可能出现下面的状况:
1、 假设哲学家吃饭的时候会首先取得自己左侧的筷子,可能在某一瞬间 5个人同时吃饭并 同时拿起了左面的筷子,得不到另一支筷子时就放下了筷子并同时拿起了自己右侧的筷子,如此反复循环。。。导致程序无法向前运行。
2、假设哲学家吃饭的时候首先拿取左侧的筷子,再检查右侧的筷子 ,如果右侧的筷子不用,则放下自己已经取得的筷子,过一段时间后在重复这一个过程。这个方法看似可行,仔细一想却和1中的情况差不多,可能在某一个瞬间,5个人同时启用这个方法,又会出现1中的情况。。。程序还是不会运行。
为了避免出现这种情况,有了哲学家算法,其中一种方案是:
1、3、5(奇数)号哲学家会分别先取离自己最近的奇数号筷子,然后再取离自己最近的右侧的筷 子,2、4(偶数)号则分别取右侧最近的奇数号筷子,再去竞争离自己最近 的偶数号筷子 。哲学家会先竞争奇数位上的筷子,再去竞争偶数位上的筷子,总有一个能吃上饭,且根据FIFO队列,其他等待的哲学家会依次得到筷子吃饭故,可以实现程序的正常运行。具体代码如下:
package Philosopher;
public class Semaphore {
int count;//共享的资源数的数量。
public Semaphore (int count){
this.count=count;
}
//操作系统p操作
public synchronized void P(){
count--;
if(count<0){//如果资源小于0,则加入等待队列中,为阻塞状态。
try {
wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
//操作系统v操作
public synchronized void V(){
count++;
if(count<=0){//如果不大于0,则唤醒等待的线程。
notify();
}
}
}
上面出现的P操作和V操作是一组运行过程中不可停止的原始操作,属于计算机原语。具体知识见操作系统原理。
public class Philosopher extends Thread{
private int n;
public Philosopher(int n){
this.n=n;
}
//重写run方法
public void run(){
/**
* 拿筷子的时候,约定:
* Philosopher编号为奇数的先取自己右边的筷子,编号为偶数的先取自己左边的筷子。
*/
while(true){
if(n%2==0){
System.out.println("Philosopher"+n+"尝试取得"+(n+1)%5+"支筷子 ");
Starteat .chopsticks[(n+1)%5].P();
System.out.println("Philosopher"+n+"已经取得"+(n+1)%5+"支筷子");
System.out.println("Philosopher"+n+"尝试取得"+(n)%5+"支筷子");
Starteat .chopsticks[(n)%5].P();
System.out.println("Philosopher"+n+"已经取得"+(n)%5+"支筷子");
System.out.println("Philosopher"+n+"正在吃饭中。。。。。。");
try {
Thread.sleep(1);//吃饭时间。。
} catch (InterruptedException e) {
e.printStackTrace();
}
Starteat .chopsticks[(n+1)%5].V();
Starteat .chopsticks[(n)%5].V();
System.out.println("Philosopher"+n+"放下了第"+n+"和"+n+1);
System.out.println("Philosopher"+n+"已经进食完毕。开始思考。。。。");
}
else {
System.out.println("Philosopher"+n+"尝试取得"+(n)%5+"支筷子");
Starteat .chopsticks[(n)%5].P();
System.out.println("Philosopher"+n+"已经取得"+(n)%5+"支筷子");
System.out.println("Philosopher"+n+"尝试取得"+(n+1)%5+"支筷子");
Starteat .chopsticks[(n+1)%5].P();
System.out.println("Philosopher"+n+"已经取得"+(n+1)%5+"支筷子");
System.out.println("Philosopher"+n+"正在吃饭中。。。。。。");
try {
Thread.sleep(1);//吃饭时间。。
} catch (InterruptedException e) {
e.printStackTrace();
}
Starteat .chopsticks[(n+1)%5].V();
Starteat .chopsticks[(n)%5].V();
System.out.println("Philosopher"+n+"放下了第"+n+"和"+n+1);
System.out.println("Philosopher"+n+"已经进食完毕。开始思考。。。。");
}
}
}
}
由于两个人之间是竞争一支筷子,所以semaphore设置为1.
package Philosopher;
public class Starteat {
static Semaphore [] chopsticks = new Semaphore [5];
public static void main(String [] agrs){
for(int i=0;i<5;i++){
chopsticks[i] = new Semaphore(1);
}
for(int i=0;i<5;i++){
new Philosopher(i).start();
}
}
}
代码实现起来比较容易,这种方法只是哲学家算法中的一种,你也可以限制同时吃饭的人数(如最多只能允许4人同时吃饭 )来解决哲学家吃饭饿死的问题。只是效率会不同。本人水平有限,不足之处请大家多多包涵。