哲學家就餐問題 Java語言實現
阿新 • • 發佈:2019-02-06
1. 哲學家就餐問題描述
本文部分內容來源於此,欲瞭解詳細內容,自行點選檢視。
為了不失一般性,我們假設有n個哲學家,圍著餐桌思考宇宙、人生問題,每個哲學家面前有一個叉子與之對應,即:共有n個叉子;當哲學家思考一段時間後,他會拿起身邊的2個叉子才能進食。進食完畢後,該哲學家放下叉子,繼續思考人生、宇宙,如此往復,周而復始。
2. 解決方案
在解決該類問題時,屬於競爭資源情形,假設所有哲學家均同時取得其同一方向(如左手邊)的叉子時,可能出現了死鎖問題。
死鎖:死鎖是這樣一種情形,當每個程序都已經佔據某個資源,同時等待另一個資源時,因為條件無法滿足而使系統停滯的現象。
活鎖:一個執行緒響應另一個執行緒的請求,同時另一個執行緒響應其他執行緒的請求。執行緒之間為響應互相的請求而實際未做任何實際工作,從而使得系統陷入飢餓狀態。例項:2人A和B在走廊相向而行,A向左邊移動讓B通過,B向右邊移動讓A通過,然後反轉,周而復始,實際上2人都被對方阻塞。
package com.fqyuan.philosophy;
public class Philosopher implements Runnable {
// The forks on either side of this Philosopher
private Object leftFork;
private Object rightFork;
public Philosopher(Object leftFork, Object rightFork) {
this.leftFork = leftFork;
this.rightFork = rightFork;
}
private void doAction(String action) throws InterruptedException {
System.out.println(Thread.currentThread().getName() + " " + action);
Thread.sleep((int) (Math.random() * 100));
}
@Override
public void run() {
try {
while (true) {
// Thinking
doAction(System.nanoTime() + ": Thinking" );
synchronized (leftFork) {
doAction(System.nanoTime() + ": Picked up left fork.");
synchronized (rightFork) {
// Eating
doAction(System.nanoTime() + ": Picked up right fork - eating.");
// Finish eating
doAction(System.nanoTime() + ": Put down right fork.");
}
// Back to thinking.
doAction(System.nanoTime() + ": Put down left fork. Back to thinking.");
}
}
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
return;
}
}
}
//DiningPhilosopers.java
package com.fqyuan.philosophy;
public class DinningPhilosophers {
public static void main(String[] args) {
Philosopher[] philosophers = new Philosopher[5];
Object[] forks = new Object[philosophers.length];
for (int i = 0; i < forks.length; i++)
forks[i] = new Object();
for (int i = 0; i < philosophers.length; i++) {
Object leftFork = forks[i];
Object rightFork = forks[(i + 1) % forks.length];
philosophers[i] = new Philosopher(leftFork, rightFork);
Thread t = new Thread(philosophers[i], "Philosopher " + (i + 1));
t.start();
}
}
}
Philosopher 1 73695516987788: Thinking
Philosopher 3 73695517303786: Thinking
Philosopher 2 73695517036856: Thinking
Philosopher 4 73695517958611: Thinking
Philosopher 5 73695518115243: Thinking
Philosopher 4 73695531258038: Picked up left fork.
Philosopher 3 73695556574779: Picked up left fork.
Philosopher 1 73695556574779: Picked up left fork.
Philosopher 5 73695591774360: Picked up left fork.
Philosopher 2 73695617427502: Picked up left fork.
Q:如何避免死鎖發生呢?
A:打破迴圈等待條件,做如下修改。
package com.fqyuan.philosophy;
public class DinningPhilosophers {
public static void main(String[] args) {
Philosopher[] philosophers = new Philosopher[5];
Object[] forks = new Object[philosophers.length];
for (int i = 0; i < forks.length; i++)
forks[i] = new Object();
for (int i = 0; i < philosophers.length; i++) {
Object leftFork = forks[i];
Object rightFork = forks[(i + 1) % forks.length];
// Let the last philosopher get the fork in the reversed order to
// break the circular waiting condition.
if (i == philosophers.length - 1) // Add the line here.
philosophers[i] = new Philosopher(rightFork, leftFork);
else
philosophers[i] = new Philosopher(leftFork, rightFork);
Thread t = new Thread(philosophers[i], "Philosopher " + (i + 1));
t.start();
}
}
}