哲学家算法
操作系统中,为了避免互斥资源使用导致死锁 问题,有很多的解决方法,其中一种方法就是哲学家算法。
首先说一下什么是哲学家算法,有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人同时吃饭 )来解决哲学家吃饭饿死的问题。只是效率会不同。本人水平有限,不足之处请大家多多包涵。