哲学家算法

哲学家算法

 

 

              操作系统中,为了避免互斥资源使用导致死锁 问题,有很多的解决方法,其中一种方法就是哲学家算法。

              首先说一下什么是哲学家算法,有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人同时吃饭 )来解决哲学家吃饭饿死的问题。只是效率会不同。本人水平有限,不足之处请大家多多包涵。

 

 

 

猜你喜欢

转载自xd-zhang.iteye.com/blog/1732611
今日推荐