题目描述(哲学家进餐问题)
五个科学家围着圆桌吃意面,叉子放在科学家之间的桌子上,叉子也是5个,每个科学家只有同时拿到两边的叉子才能吃面。设计并行算法,使得科学家都不会挨饿。
这道题的难点在于死锁,复习一下死锁的条件:
- 互斥条件
- 请求与保持条件
- 不可剥夺条件
- 循环等待条件
这样比如一旦所有的科学家同时拿起左边的叉子都不释放,那么所有的科学家都将无法吃面。
因此只需要设计算法破坏死锁的条件即可。
代码如下:
class DiningPhilosophers {
// 叉子是同时只能被一个科学家占用的资源,每个叉子用一个信号量表示
private List<Semaphore> forks = new ArrayList<>();
public DiningPhilosophers() {
for(int i = 0; i < 5; ++i){
forks.add(new Semaphore(1));
}
}
// 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 {
for(;;) { //自旋获取叉子
forks.get(philosopher).acquire(); //拿左边的叉子
try {
int idx = (philosopher + 1) % 5;
// 尝试获取右边的叉子, 如果没有获取到,则放下已经拿到的左边的叉子,破坏不可剥夺条件
if (forks.get(idx).tryAcquire()) {
try {
pickLeftFork.run();
pickRightFork.run();
eat.run();
putRightFork.run();
putLeftFork.run();
} finally {
forks.get(idx).release();
}
break;
}
} finally {
forks.get(philosopher).release();
}
}
}
}