经典死锁案例-哲学家就餐

死锁经典案例:哲学家就餐。

这个案例会导致死锁

通过修改《Java编程思想4》一书中的案例,来做实验,代码更易理解,结果也相对容易控制。

附代码:

筷子类:

package com.tyxh.ch21.c6;

public class Chopstick {
	private boolean taken = false;//判断是此筷子是否被拿起
	public synchronized void take() throws InterruptedException {
		while(taken) {
			//如果已被拿起,则等待
			wait();
		}
		//如果没有被拿起,则可以被拿起,并设置taken为true
		taken = true;
	}
	
	public synchronized void drop() {
		//放下筷子之后设置taken为false,并通知其他筷子
		taken = false;
		notifyAll();
	}
}

哲学家类:

package com.tyxh.ch21.c6;

import java.util.Random;
import java.util.concurrent.TimeUnit;

public class Philosopher implements Runnable {
	private Chopstick left;//左筷子
	private Chopstick right;//右筷子
	
	private final int id;//哲学家编号
	private final int ponderFactor;//根据这个属性设置思考时间
	
	private Random rand = new Random(47);
	private void pause() throws InterruptedException {
		if(ponderFactor == 0) {
			return;
		}
		TimeUnit.MILLISECONDS.sleep(rand.nextInt(ponderFactor *250));
	}
	
	public Philosopher(Chopstick left, Chopstick right, int ident, int ponder) {
		this.left = left;
		this.right = right;
		this.id = ident;
		this.ponderFactor = ponder;
	}
	
	public void run() {
		try{
			while(!Thread.interrupted()) {
				System.out.println(this + " " + "thinking");
				pause();
				right.take();
				System.out.println(this + " " + "拿右筷子");
				left.take();
				System.out.println(this + " " + "拿左筷子");
				pause();
				System.out.println(this + " " + "吃");
				right.drop();
				System.out.println(this + " " + "放下右筷子");
				left.drop();
				System.out.println(this + " " + "放下左筷子");
			}
		}catch(InterruptedException e) {
			System.out.println(this + " 退出   ");
		}
	}
	
	public String toString() {
		return "Phiosopher : " + id; 
 	}
}

测试类:

package com.tyxh.ch21.c6;

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;

public class DeadlockingDiningPhilosophers {
	public static void main(String[] args) throws InterruptedException {
		int ponder = 5;
		if(args.length > 0) {
			ponder = Integer.parseInt(args[0]);
		}
		int size = 5;
		if(args.length > 1) {
			size = Integer.parseInt(args[1]);
		}
		ExecutorService exec = Executors.newCachedThreadPool();
		Chopstick[] stick = new Chopstick[size];
		
		for(int i = 0; i < size; i++) {
			stick[i] = new Chopstick();
		}
		
		for(int i = 0; i < size; i++) {
			Philosopher p = new Philosopher(stick[i], stick[(i+1)%size], i, ponder);
			exec.execute(p);
		}
		
		TimeUnit.SECONDS.sleep(3);
		exec.shutdownNow();
		
	}
}
 

可以通过命令行参数调整ponder因子设置哲学家思考时间,也可以设置筷子及哲学家的数量size。


这里仅给出书中处理此死锁的解决方案:

方案是:

前面哲学家拿筷子的顺序都是先拿右,再拿左,但最后一个哲学家拿筷子的顺序是先拿左,再拿右,就可以通过阻止循环等待这个死锁的条件来阻止死锁发生。

即将代码:

		for(int i = 0; i < size; i++) {
			Philosopher p = new Philosopher(stick[i], stick[(i+1)%size], i, ponder);
			exec.execute(p);
		}


修改为:

		for(int i = 0; i < size; i++) {
			if(i < size - 1) {
				Philosopher p = new Philosopher(stick[i], stick[(i+1)%size], i, ponder);
				exec.execute(p);
			}else {
				Philosopher p = new Philosopher(stick[0], stick[i], i, ponder);
				exec.execute(p);
			}
		}




阅读更多
想对作者说点什么?

博主推荐

换一批

没有更多推荐了,返回首页