哲學家就餐問題Java版解決案
阿新 • • 發佈:2019-01-05
關於Java多執行緒的經典問題:哲學家就餐問題。以前在網上找過很多例子,執行的效果都不盡人意。於是閱讀了一些多執行緒的書寫了一個解決案。
因為接觸多執行緒時間不長,寫出來的東西還請大牛們多多指教。
問題描述:哲學家就餐問題可以這樣表述,假設有五位哲學家圍坐在一張圓形餐桌旁,做以下兩件事情之一:吃飯,或者思考。吃東西的時候,他們就停止思考,思考的時候也停止吃東西。餐桌中間有一大碗義大利麵,每兩個哲學家之間有一隻餐叉。因為用一隻餐叉很難吃到義大利麵,所以假設哲學家必須用兩隻餐叉吃東西。他們只能使用自己左右手邊的那兩隻餐叉。哲學家就餐問題有時也用米飯和筷子而不是義大利麵和餐叉來描述,因為很明顯,吃米飯必須用兩根筷子。
哲學家從來不交談,這就很危險,可能產生死鎖,每個哲學家都拿著左手的餐叉,永遠都在等右邊的餐叉(或者相反)。即使沒有死鎖,也有可能發生資源耗盡。例如,假設規定當哲學家等待另一隻餐叉超過五分鐘後就放下自己手裡的那一隻餐叉,並且再等五分鐘後進行下一次嘗試。這個策略消除了死鎖(系統總會進入到下一個狀態),但仍然有可能發生“活鎖”。如果五位哲學家在完全相同的時刻進入餐廳,並同時拿起左邊的餐叉,那麼這些哲學家就會等待五分鐘,同時放下手中的餐叉,再等五分鐘,又同時拿起這些餐叉。
在實際的計算機問題中,缺乏餐叉可以類比為缺乏共享資源。一種常用的計算機技術是資源加鎖,用來保證在某個時刻,資源只能被一個程式或一段程式碼訪問。當一個程式想要使用的資源已經被另一個程式鎖定,它就等待資源解鎖。當多個程式涉及到加鎖的資源時,在某些情況下就有可能發生死鎖。例如,某個程式需要訪問兩個檔案,當兩個這樣的程式各鎖了一個檔案,那它們都在等待對方解鎖另一個檔案,而這永遠不會發生。
public class PerThread extends Thread {
public static void main(String... arg){
Copsticks cop = new Copsticks();
for(int i = 0; i < 5; i++){
PerThread per = new PerThread(i, cop);
per.start();
}
}
private int index;
private int count = 0;
private boolean lefCop = false;
private boolean rightCop = false;
private Copsticks cop = new Copsticks();
public PerThread(int index, Copsticks cop){
this.index = index;
this.cop = cop;
}
public void run() {
// 預設吃5次以後哲學家吃飽
while (count < 5 ) {
// 哲學家在思考
thinking();
// 監測筷子並獲取筷子,否則等待
takeCopsticks();
// 獲取筷子後吃飯
eat();
// 吃完後放下筷子
putCopsticks();
}
System.out.println("哲學家" + index + ":吃飽了!");
}
// 哲學家思考
private void thinking(){
try {
System.out.println("哲學家" + index + ":在思考。。。。");
sleep((int)Math.abs(Math.random() * 1000));
System.out.println("哲學家" + index + ":思考結束!");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
// 哲學家吃飯
private void eat(){
try {
System.out.println("哲學家" + index + ":在吃飯。。。。");
count++;
sleep((int)Math.abs(Math.random() * 1000));
System.out.println("哲學家" + index + ":吃飯結束!");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
public int getIndex() {
return index;
}
public void setIndex(int index) {
this.index = index;
}
public boolean isLefCop() {
return lefCop;
}
public void setLefCop(boolean lefCop) {
this.lefCop = lefCop;
}
public boolean isRightCop() {
return rightCop;
}
public void setRightCop(boolean rightCop) {
this.rightCop = rightCop;
}
// 獲取筷子
public void takeCopsticks(){
// synchronized關鍵字給共享資源Copsticks加鎖
synchronized(cop){
PerThread per = (PerThread)Thread.currentThread();
int index = per.getIndex();
while(cop.used[index] && cop.used[(index + 1) % 5]){
try {
System.out.println("哲學家" + index + ":無法獲得筷子!在等待。。。");
// 執行共享物件的wait()發放,讓執行緒在cop物件上等待
cop.wait();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
cop.used[index] = true;
System.out.println("哲學家" + index + ":獲得左快子!");
per.setLefCop(true);
cop.used[(index + 1) % 5] = true;
System.out.println("哲學家" + index + ":獲得右快子!");
per.setRightCop(true);
}
}
// 釋放筷子
public void putCopsticks(){
// synchronized關鍵字給共享資源Copsticks加鎖
synchronized(cop){
PerThread per = (PerThread)Thread.currentThread();
int index = per.getIndex();
cop.used[index] = false;
System.out.println("哲學家" + index + ":放下左快子!");
per.setLefCop(false);
cop.used[(index + 1) % 5] = false;
System.out.println("哲學家" + index + ":放下右快子!");
per.setRightCop(false);
// 執行共享物件cop的notifyAll()方法,喚醒在這個物件cop上等待的執行緒
cop.notifyAll();
}
}
}
/**
*筷子類
*/
class Copsticks{
public boolean[] used = {false,false,false,false,false};
}