这是避免死锁的一个经典题目,虽然算法知道,但是一直没有写过代码,这里总结一下主要的实现方法。
方法一,限制每次只能有一个哲学家吃饭,这种方法效率比较低,但是实现起来很简单,就是采用一个全局锁。本质上是同时获取所有的资源,而不是分步获取资源,打破持有并等待。
class DiningPhilosophers1 {
ReentrantLock lock=new ReentrantLock();
public DiningPhilosophers1() {
}
// call the run() method of any runnable to execute its code
public void wantsToEat(int philosopher,
Runnable pickLeftFork,
Runnable pickRightFork,
Runnable eat,
Runnable putLeftFork,
Runnable putRightFork) throws InterruptedException {
lock.lock();
pickLeftFork.run();
pickRightFork.run();
eat.run();
putLeftFork.run();
putRightFork.run();
lock.unlock();
}
}
方法二、规定序号为奇数的哲学家先拿左边的叉子,再拿右边的叉子,序号为偶数的哲学家则反过来,这样能够保证不会出现5个哲学家同时拿到左边叉子或右边叉子的死锁情况。打破循环等待的问题。
class DiningPhilosophers2 {
ReentrantLock[] locks=new ReentrantLock[5];//5只叉子的锁
public DiningPhilosophers2() {
for(int i=0;i<5;i++){
locks[i]=new ReentrantLock();
}
}
// call the run() method of any runnable to execute its code
public void wantsToEat(int philosopher,
Runnable pickLeftFork,
Runnable pickRightFork,
Runnable eat,
Runnable putLeftFork,
Runnable putRightFork) throws InterruptedException {
if((philosopher&1)==1){
locks[philosopher].lock();
locks[(philosopher-1+5)%5].lock();
}else{
locks[(philosopher-1+5)%5].lock();
locks[philosopher].lock();
}
pickLeftFork.run();
pickRightFork.run();
eat.run();
putLeftFork.run();
putRightFork.run();
locks[philosopher].unlock();
locks[(philosopher-1+5)%5].unlock();
}
}
方法三,限制同时吃饭的人数不超过4个人,这样总会产生两个人竞争一把叉子并竞争成功的情况,避免循环等待。
class DiningPhilosophers {
Semaphore semaphore=new Semaphore(4);
ReentrantLock[] locks=new ReentrantLock[5];
public DiningPhilosophers() {
for(int i=0;i<5;i++){
locks[i]=new ReentrantLock();
}
}
// call the run() method of any runnable to execute its code
public void wantsToEat(int philosopher,
Runnable pickLeftFork,
Runnable pickRightFork,
Runnable eat,
Runnable putLeftFork,
Runnable putRightFork) throws InterruptedException {
semaphore.acquire();
locks[philosopher].lock();
locks[(philosopher-1+5)%5].lock();
pickLeftFork.run();
pickRightFork.run();
eat.run();
putLeftFork.run();
putRightFork.run();
locks[philosopher].unlock();
locks[(philosopher-1+5)%5].unlock();
semaphore.release();
}
}