設(shè)計題目:哲學家進餐問題
目前累計服務客戶近千家,積累了豐富的產(chǎn)品開發(fā)及服務經(jīng)驗。以網(wǎng)站設(shè)計水平和技術(shù)實力,樹立企業(yè)形象,為客戶提供成都網(wǎng)站制作、成都網(wǎng)站建設(shè)、外貿(mào)營銷網(wǎng)站建設(shè)、網(wǎng)站策劃、網(wǎng)頁設(shè)計、網(wǎng)絡(luò)營銷、VI設(shè)計、網(wǎng)站改版、漏洞修補等服務。創(chuàng)新互聯(lián)始終以務實、誠信為根本,不斷創(chuàng)新和提高建站品質(zhì),通過對領(lǐng)先技術(shù)的掌握、對創(chuàng)意設(shè)計的研究、對客戶形象的視覺傳遞、對應用系統(tǒng)的結(jié)合,為客戶提供更好的一站式互聯(lián)網(wǎng)解決方案,攜手廣大客戶,共同發(fā)展進步。
一、 設(shè)計題目:哲學家進餐問題
二、 設(shè)計要求
1、 分析題目
哲學家有N個,也定全體到齊后開始討論,在討論的間隙哲學家進餐,(1)每個人只能拿起位于自己兩邊放著的刀、叉,合成一對才可以用餐;(2)用餐后每人必須將刀、叉放回原處。可以想象,如果每個哲學家都彬彬有禮,并且高談闊論,輪流吃飯,則這種融洽的氣氛可以長久地保持下去。但可能出現(xiàn)這樣一種情景:當每個人都拿起自己左手的刀(叉),并且同時去拿自己右手邊的叉(刀)時,會發(fā)生什么情況:每個人拿著一支餐具,盯著自己右手邊的那位哲學家手里的一支餐具,處于僵持狀態(tài)。這就是發(fā)生了“線程死鎖”。需要指出的是,線程死鎖并不是必然會發(fā)生,在某些情況下,可能會非常偶然。
2、 解決方案
一般來說,要出現(xiàn)死鎖必須同時據(jù)別以下4個條件。因此,只要能夠盡可能地破壞這4個條件中的任意一個,就可以避免死鎖的出現(xiàn)。(1)互斥條件,即至少存在一個資源,不能被多個線程同時共享。(2)至少存在一個線程,它擁有一個資源,并等待獲得另一個線程當前所擁有的資源。(3)線程擁有的資源不能被強行剝奪,只能有線程資源釋放。(4)線程對資源的請求形成一個環(huán)。
三、 源代碼
//DishWare.java
//定義一個DishWareBean進行屬性和方法封裝
public class DishWare
{
private String name;
public DishWare(String name)
{
this.name=name;
}
public String getNumber()
{
return name;
}
}
//Philospher.java
import java.util.*; //包含常用的數(shù)據(jù)類型類
public class Philospher extends Thread
{
private DishWare Knife;
private DishWare Fork;
private String name;
private static Random random=new Random();
public Philospher(String name,DishWare Knife,DishWare Fork) //構(gòu)造函數(shù),變量初始化
{
this.name=name;
this.Knife=Knife;
this.Fork=Fork;
}
public String getNumber()
{
return name;
}
public void run() //多線程的實現(xiàn)方法run()
{
try{
sleep(random.nextInt(3));
}
catch(InterruptedException e){}
synchronized(Knife){ //線程的同步,使用synchronized關(guān)鍵詞
System.out.println(this.getNumber()+" has "+Knife.getNumber()+" and wait for "+Fork.getNumber());
synchronized(Fork){
System.out.println(this.getNumber()+" eating");
}
}
}
public static void main(String args[])
{
//建立刀叉對象
DishWare knife1=new DishWare("Knife1");
DishWare fork1=new DishWare("Fork1");
DishWare knife2=new DishWare("Knife2");
DishWare fork2=new DishWare("Fork2");
//建立哲學家對象,并在其兩邊擺放刀叉
Philospher philospher1=new Philospher("philospher1",knife1,fork1);
Philospher philospher2=new Philospher("philospher2",fork1,knife2);
Philospher philospher3=new Philospher("philospher3",knife2,fork2);
Philospher philospher4=new Philospher("philospher4",fork2,knife1);
//啟動3個線程,用start方法開始線程
philospher1.start();
philospher2.start();
philospher3.start();
philospher4.start();
}
}
# define N 5 /* 哲學家數(shù)目 */
# define LEFT (i-1+N)%N /* i的左鄰號碼 */
# define RIGHT (i+1)%N /* i的右鄰號碼 */
# define THINKING 0 /* 哲學家正在思考 */
# define HUNGRY 1 /* 哲學家想取得叉子 */
# define EATING 2 /* 哲學家正在吃面 */
typedef int semaphore; /* 信號量是一個特殊的整型變量 */
int state[N]; /* 記錄每個人狀態(tài)的數(shù)組 */
semaphore mutex=1; /* 臨界區(qū)互斥 */
semaphore s[N]; /* 每個哲學家一個信號量 */
void philosopher(int i) /* i:哲學家號碼,從0到N-1 */
{
while(TRUE)
{ /* 無限循環(huán) */
think(); /* 哲學家正在思考 */
take_forks(i);
/* 需要兩只叉子,或者阻塞 */
eat(); /* 進餐 */
put_forks(i);
/* 把兩把叉子同時放回桌子 */
}
}
void take_forks(int i) /* i:哲學家號碼從0到N-1 */
{
down(mutex); /* 進入臨界區(qū) */
state[i]=HUNGRY; /* 記錄下哲學家i饑餓的事實 */
test(i); /* 試圖得到兩只叉子 */
up(mutex); /* 離開臨界區(qū) */
down(s[i]); /* 如果得不到叉子就阻塞 */
}
void put_forks(int I) /* i:哲學家號碼從0到N-1 */
{
down(mutex); /* 進入臨界區(qū) */
state[i]=THINKING; /* 哲學家進餐結(jié)束 */
test(LEFT); /* 看一下左鄰居現(xiàn)在是否能進餐 */
test(RIGHT); /* 看一下右鄰居現(xiàn)在是否能進餐 */
up(mutex); /* 離開臨界區(qū) */
}
void test(i) /* i:哲學家號碼從0到N-1 */
{
if(state[i]==HUNGRYstate[LEFT]!=EATING
state[RIGHT]!=EATING)
{
state[i]=EATING;
up(s[i]);
}
}
1.哲學家進餐問題:
(1) 在什么情況下5 個哲學家全部吃不上飯考慮兩種實現(xiàn)的方式,如下:
A. 算法描述: void philosopher(int i) /*i:哲學家編號,從0 到4*/ {while (TRUE) { think( ); /*哲學家正在思考*/ take_fork(i); /*取左側(cè)的筷子*/ take_fork((i+1) % N); /*取左側(cè)筷子;%為取模運算*/eat( ); /*吃飯*/put_fork(i); /*把左側(cè)筷子放回桌子*/ put_fork((i+1) % N); /*把右側(cè)筷子放回桌子*/ } } 分析:假如所有的哲學家都同時拿起左側(cè)筷子,看到右側(cè)筷子不可用,又都放下左側(cè)筷子,等一會兒,又同時拿起左側(cè)筷子,如此這般,永遠重復。對于這種情況,即所有的程序都在無限期地運行,但是都無法取得任何進展,即出現(xiàn)饑餓,所有哲學家都吃不上飯。
B.算法描述:規(guī)定在拿到左側(cè)的筷子后,先檢查右面的筷子是否可用。如果不可用,則先放下左側(cè)筷子,等一段時間再重復整個過程。分析:當出現(xiàn)以下情形,在某一個瞬間,所有的哲學家都同時啟動這個算法,拿起左側(cè)的筷子,而看到右側(cè)筷子不可用,又都放下左側(cè)筷子,等一會兒,又同時拿起左側(cè)筷子……如此這樣永遠重復下去。對于這種情況,所有的程序都在運行,但卻無法取得進展,即出現(xiàn)饑餓,所有的哲學家都吃不上飯。
(2) 描述一種沒有人餓死(永遠拿不到筷子)算法。考慮了四種實現(xiàn)的方式(A、B、C、D):
A.原理:至多只允許四個哲學家同時進餐,以保證至少有一個哲學家能夠進餐,最終總會釋放出他所使用過的兩支筷子,從而可使更多的哲學家進餐。以下將room 作為信號量,只允許4 個哲學家同時進入餐廳就餐,這樣就能保證至少有一個哲學家可以就餐,而申請進入餐廳的哲學家進入room 的等待隊列,根據(jù)FIFO 的原則,總會進入到餐廳就餐,因此不會出現(xiàn)餓死和死鎖的現(xiàn)象。
偽碼: semaphore chopstick[5]={1,1,1,1,1}; semaphore room=4; void philosopher(int i) { while(true) {think(); wait(room); //請求進入房間進餐 wait(chopstick[i]); //請求左手邊的筷子 wait(chopstick[(i+1)%5]); //請求右手邊的筷子 eat(); signal(chopstick[(i+1)%5]); //釋放右手邊的筷子 signal(chopstick[i]); //釋放左手邊的筷子 signal(room); //退出房間釋放信號量room } }
B.原理:僅當哲學家的左右兩支筷子都可用時,才允許他拿起筷子進餐。
方法1:利用AND 型信號量機制實現(xiàn):根據(jù)課程講述,在一個原語中,將一段代碼同時需要的多個臨界資源,要么全部分配給它,要么一個都不分配,因此不會出現(xiàn)死鎖的情形。當某些資源不夠時阻塞調(diào)用進程;由于等待隊列的存在,使得對資源的請求滿足FIFO 的要求,因此不會出現(xiàn)饑餓的情形。
偽碼: semaphore chopstick[5]={1,1,1,1,1}; void philosopher(int I) { while(true) { think();Swait(chopstick[(I+1)]%5,chopstick[I]); eat(); Ssignal(chopstick[(I+1)]%5,chopstick[I]);} } 方法2:利用信號量的保護機制實現(xiàn)。通過信號量mutex對eat()之前的取左側(cè)和右側(cè)筷子的操作進行保護,使之成為一個原子操作,這樣可以防止死鎖的出現(xiàn)。偽碼: semaphore mutex = 1 ; semaphorechopstick[5]={1,1,1,1,1};void philosopher(int I) { while(true) { think(); wait(mutex);wait(chopstick[(I+1)]%5); wait(chopstick[I]); signal(mutex); eat();signal(chopstick[(I+1)]%5); signal(chopstick[I]); } }
C.原理:規(guī)定奇數(shù)號的哲學家先拿起他左邊的筷子,然后再去拿他右邊的筷子;而偶數(shù)號的哲學家則相反.按此規(guī)定,將是1,2號哲學家競爭1號筷子,3,4號哲學家競爭3號筷子.即五個哲學家都競爭奇數(shù)號筷子,獲得后,再去競爭偶數(shù)號筷子,最后總會有一個哲學家能獲得兩支筷子而進餐。而申請不到的哲學家進入阻塞等待隊列,根FIFO原則,則先申請的哲學家會較先可以吃飯,因此不會出現(xiàn)餓死的哲學家。
偽碼: semaphore chopstick[5]={1,1,1,1,1}; void philosopher(int i) { while(true) { think(); if(i%2== 0) //偶數(shù)哲學家,先右后左。 { wait (chopstick[ i + 1 ] mod 5) ; wait (chopstick[ i]) ;eat(); signal (chopstick[ i + 1 ] mod 5) ; signal (chopstick[ i]) ; } Else //奇數(shù)哲學家,先左后右。 { wait (chopstick[ i]) ; wait (chopstick[ i +1 ] mod 5) ; eat(); signal (chopstick[ i]) ; signal (chopstick[ i + 1 ] mod 5); } }
D.利用管程機制實現(xiàn)(最終該實現(xiàn)是失敗的,見以下分析):原理:不是對每只筷子設(shè)置信號量,而是對每個哲學家設(shè)置信號量。test()函數(shù)有以下作用:
a. 如果當前處理的哲學家處于饑餓狀態(tài)且兩側(cè)哲學家不在吃飯狀態(tài),則當前哲學家通過 test()函數(shù)試圖進入吃飯狀態(tài)。
b. 如果通過test()進入吃飯狀態(tài)不成功,那么當前哲學家就在該信號量阻塞等待,直到其他的哲學家進程通過test()將該哲學家的狀態(tài)設(shè)置為EATING。
c. 當一個哲學家進程調(diào)用put_forks()放下筷子的時候,會通過test()測試它的鄰居,如果鄰居處于饑餓狀態(tài),且該鄰居的鄰居不在吃飯狀態(tài),則該鄰居進入吃飯狀態(tài)。由上所述,該算法不會出現(xiàn)死鎖,因為一個哲學家只有在兩個鄰座都不在進餐時,才允許轉(zhuǎn)換到進餐狀態(tài)。該算法會出現(xiàn)某個哲學家適終無法吃飯的情況,即當該哲學家的左右兩個哲學家交替處在吃飯的狀態(tài)的時候,則該哲學家始終無法進入吃飯的狀態(tài),因此不滿足題目的要求。但是該算法能夠?qū)崿F(xiàn)對于任意多位哲學家的情況都能獲得最大的并行度,因此具有重要的意義。
偽碼:#define N 5 /* 哲學家人數(shù)*/#define LEFT (i-1+N)%N /* i的左鄰號碼 */ #define RIGHT (i+1)%N /* i的右鄰號碼 */ typedef enum { THINKING, HUNGRY, EATING } phil_state; /*哲學家狀態(tài)*/ monitor dp /*管程*/ { phil_state state[N]; semaphore mutex =1; semaphore s[N];/*每個哲學家一個信號量,初始值為0*/void test(int i) { if ( state[i] == HUNGRY state[LEFT(i)] != EATING state[RIGHT(i)] != EATING ) { state[i] = EATING; V(s[i]); } } void get_forks(inti) { P(mutex); state[i] = HUNGRY; test(i); /*試圖得到兩支筷子*/ V(mutex); P(s[i]); /*得不到筷子則阻塞*/ } void put_forks(int i) { P(mutex); state[i]= THINKING;test(LEFT(i)); /*看左鄰是否進餐*/ test(RIGHT(i)); /*看右鄰是否進餐*/ V(mutex); } } 哲學家進程如下: void philosopher(int process) { while(true) { think();get_forks(process); eat(); put_forks(process); } }
2.理發(fā)師問題:一個理發(fā)店有一個入口和一個出口。理發(fā)店內(nèi)有一個可站5 位顧客的站席區(qū)、4 個單人沙發(fā)、3 個理發(fā)師及其專用理發(fā)工具、一個收銀臺。新來的顧客坐在沙發(fā)上等待;沒有空沙發(fā)時,可在站席區(qū)等待;站席區(qū)滿時,只能在入口外等待。理發(fā)師可從事理發(fā)、收銀和休息三種活動。
理發(fā)店的活動滿足下列條件:
1)休息的理發(fā)師是坐地自己專用的理發(fā)椅上,不會占用顧客的沙發(fā);
2)處理休息狀態(tài)的理發(fā)師可為在沙發(fā)上等待時間最長的顧客理發(fā);
3)理發(fā)時間長短由理發(fā)師決定;
4)在站席區(qū)等待時間最長的顧客可坐到空閑的理發(fā)上;
5)任何時刻最多只能有一個理發(fā)師在收銀。試用信號量機制或管程機制實現(xiàn)理發(fā)師進程和顧客進程。
原理:
(1) customer 進程:首先檢查站席區(qū)是否已滿(stand_capacity),若滿選擇離開,否則進入站席區(qū),即進入理發(fā)店。在站席區(qū)等待沙發(fā)的空位(信號量sofa),如果沙發(fā)已滿,則進入阻塞等待隊列,直到出現(xiàn)空位,在站席區(qū)中等待時間最長的顧客離開站席區(qū)(stand_capacity)。坐到沙發(fā)上,等待理發(fā)椅(barber_chair),如果理發(fā)椅已滿,則進入阻塞等待隊列,直到出現(xiàn)空位,在沙發(fā)上等待時間最長的顧客離開沙發(fā)(釋放信號量sofa)。坐到理發(fā)椅上,釋放準備好的信號(customer_ready),獲得該理發(fā)師的編號(0~1 的數(shù)字)。等待理發(fā)師理發(fā)結(jié)束(finished[barber_number])。在離開理發(fā)椅之前付款(payment),等待收據(jù) (receipt),離開理發(fā)椅(leave_barberchair)。最后離開理發(fā)店。
這里需要注意幾點:
a) 首先是幾個需要進行互斥處理的地方,主要包括:進入站席區(qū)、進入沙發(fā)、進入理發(fā)椅和付款幾個地方。
b) 通過barber_chair保證一個理發(fā)椅上最多只有一名顧客。但這也不夠,因為單憑 baber_chair 無法保證一名顧客離開理發(fā)椅之前,另一位顧客不會坐到該理發(fā)椅上,因此增加信號量leave_barberchair,讓顧客離開理發(fā)椅后,釋放該信號,而理發(fā)師接收到該信號后才釋放barber_chair 等待下一位顧客。
c) 在理發(fā)的過程中,需要保證是自己理發(fā)完畢,才能夠進行下面的付款、離開理發(fā)椅的活動。這個機制是通過customer 進程獲得給他理發(fā)的理發(fā)師編號來實現(xiàn)的,這樣,當該編號的理發(fā)師釋放對應的finished[i]信號的時候,該顧客才理發(fā)完畢。
d) 理發(fā)師是通過mutex 信號量保證他們每個人同時只進行一項操作(理發(fā)或者收款)。
e) 為了保證該顧客理發(fā)完畢后馬上可以付款離開,就應該保證給該顧客理發(fā)的理發(fā)師在理發(fā)完畢后馬上到收銀臺進入收款操作而不是給下一位顧客服務。在偽碼中由以下機制實現(xiàn):即顧客在釋放離開理發(fā)椅的信號前,發(fā)出付款的信號。這樣該理發(fā)師得不到顧客的離開理發(fā)椅的信號,不能進入下一個循環(huán)為下一名顧客服務,而只能進入收款臺的收款操作。直到顧客接到收據(jù)后,才釋放離開理發(fā)椅的信號,離開理發(fā)椅,讓理發(fā)師釋放該理發(fā)椅的信號,讓下一位等待的顧客坐到理發(fā)椅上。
(2)barber 進程首先將該理發(fā)師的編號壓入隊列,供顧客提取。等待顧客坐到理發(fā)椅坐好(信號量 customer_ready),開始理發(fā),理發(fā)結(jié)束后釋放結(jié)束信號(finished[i])。等待顧客離開理發(fā)椅(leave_barberchair)(期間去收銀臺進行收款活動),釋放理發(fā)椅空閑信號(barber_chair),等待下一位顧客坐上來。
(3)cash(收銀臺)進程等待顧客付款(payment),執(zhí)行收款操作,收款操作結(jié)束,給付收據(jù)(receipt)。信號量總表:信號量 waitsignal stand_capacity 顧客等待進入理發(fā)店顧客離開站席區(qū) sofa 顧客等待坐到沙發(fā)顧客離開沙發(fā) barber_chair 顧客等待空理發(fā)椅理發(fā)師釋放空理發(fā)椅 customer_ready 理發(fā)師等待,直到一個顧客坐到理發(fā)椅顧客坐到理發(fā)椅上,給理發(fā)師發(fā)出信號 mutex 等待理發(fā)師空閑,執(zhí)行理發(fā)或收款操作理發(fā)師執(zhí)行理發(fā)或收款結(jié)束,進入空閑狀態(tài) mutex1執(zhí)行入隊或出隊等待入隊或出隊結(jié)束,釋放信號 finished[i] 顧客等待對應編號理發(fā)師理發(fā)結(jié)束理發(fā)師理發(fā)結(jié)束,釋放信號 leave_barberchair 理發(fā)師等待顧客離開理發(fā)椅顧客付款完畢得到收據(jù),離開理發(fā)椅釋放信號 payment 收銀員等待顧客付款顧客付款,發(fā)出信號 receipt 顧客等待收銀員收、開具收據(jù)收銀員收款結(jié)束、開具收據(jù),釋放信號
偽碼: semaphore stand_capacity=5; semaphore sofa=4; semaphorebarber_chair=3; semaphore customer_ready=0; semaphore mutex=3; semaphoremutex1=1; semaphore finished[3]={0,0,0}; semaphore leave_barberchair=0;semaphore payment=0; semaphore receipt=0; void customer() { int barber_number;wait(stand_capacity); //等待進入理發(fā)店 enter_room(); //進入理發(fā)店 wait(sofa); //等待沙發(fā) leave_stand_section(); //離開站席區(qū) signal(stand_capacity); sit_on_sofa(); //坐在沙發(fā)上 wait(barber_chair); //等待理發(fā)椅 get_up_sofa(); //離開沙發(fā) signal(sofa); wait(mutex1);sit_on_barberchair(); //坐到理發(fā)椅上 signal(customer_ready); barber_number=dequeue(); //得到理發(fā)師編號 signal(mutex1); wait(finished[barber_number]);//等待理發(fā)結(jié)束 pay(); //付款 signal(payment); //付款 wait(receipt); //等待收據(jù) get_up_barberchair(); //離開理發(fā)椅 signal(leave_barberchair); //發(fā)出離開理發(fā)椅信號 exit_shop(); //了離開理發(fā)店 } void barber(int i) { while(true) { wait(mutex1);enqueue(i); //將該理發(fā)師的編號加入隊列 signal(mutex1); wait(customer_ready); //等待顧客準備好 wait(mutex); cut_hair(); //理發(fā) signal(mutex); signal(finished[i]); //理發(fā)結(jié)束 wait(leave_barberchair); //等待顧客離開理發(fā)椅信號 signal(barber_chair); //釋放barber_chair 信號 } } void cash() //收銀 { while(true) { wait(payment); //等待顧客付款 wait(mutex); //原子操作 get_pay(); //接受付款 give_receipt(); //給顧客收據(jù) signal(mutex); signal(receipt); //收銀完畢,釋放信號 } }
分析:在分析該問題過程中,出現(xiàn)若干問題,是參閱相關(guān)資料后才認識到這些問題的隱蔽性和嚴重性的,主要包括:
(1)在顧客進程,如果是在釋放leave_barberchair 信號之后進行付款動作的話,很容易造成沒有收銀員為其收款的情形,原因是:為該顧客理發(fā)的理發(fā)師收到 leave_barberchair 信號后,釋放barber_chair 信號,另外一名顧客坐到理發(fā)椅上,該理發(fā)師有可能為這另外一名顧客理發(fā),而沒有為剛理完發(fā)的顧客收款。為解決這個問題,就是采取在釋放leave_barberchair 信號之前,完成付款操作。這樣該理發(fā)師無法進入下一輪循環(huán)為另外顧客服務,只能到收銀臺收款。
(2)本算法是通過給理發(fā)師編號的方式,當顧客坐到某理發(fā)椅上也同時獲得理發(fā)師的編號,如此,當該理發(fā)師理發(fā)結(jié)束,釋放信號,顧客只有接收到為其理發(fā)的理發(fā)師的理發(fā)結(jié)束信號才會進行付款等操作。這樣實現(xiàn),是為避免這樣的錯誤,即:如果僅用一個finished 信號量的話,很容易出現(xiàn)別的理發(fā)師理發(fā)完畢釋放了finished 信號,把正在理發(fā)的這位顧客趕去付款,而已經(jīng)理完發(fā)的顧客卻被阻塞在理發(fā)椅上的情形。當然也可以為顧客進行編號,讓理發(fā)師獲取他理發(fā)的顧客的編號,但這樣就會限制顧客的數(shù)量,因為finished[] 數(shù)組不能是無限的。而為理發(fā)師編號,則只需要三個元素即可。
public class Scientist extends Thread {
/*
* @author Bore
* @mail z
* @time / /
* 哲學家進餐 個哲學家 只筷子
* 哲學家通過getChopsticks()方法 來取筷子
* 當哲學家同時獲得左邊和右邊兩只筷子后才可以進餐 否則把已經(jīng)得到的筷子也釋放
* 如果一直筷子也沒有 進程阻塞 等待其他哲學家釋放資源
* 進程后 釋放已經(jīng)獲得的資源
*/
static byte[] chopsticks={ };//五只筷子
public Scientist(String name){
super(name);
}
public void run() {
getChopsticks();
}
public void getChopsticks(){//開始搶筷子
int tem=Integer parseInt(this getName() substring( ));//獲取哲學家編號
if(tem== ){//如果是第一位科學家 先搶左邊的筷子
if(leftChopsticks(tem)){//如何獲取了左邊的筷子
if(rightChopsticks(tem)){//如果獲取了右邊的筷子
eating();//開始吃飯
freeLeftChopsticks(tem);//釋放左邊筷子
freeRightChopsticks(tem);//釋放右邊筷子
}else{
freeLeftChopsticks(tem);
System out println( 由于 +this getName()+ 無法獲得右手邊的筷子 所以他把已獲得的左手的筷子也釋放了! );
try {
this sleep( );
} catch (InterruptedException e) {
e printStackTrace();
}
getChopsticks();
}
}else{
System out println(this getName()+ 暫時無法獲取兩只筷子 準備休眠! );
try {
this sleep( );
} catch (InterruptedException e) {
e printStackTrace();
}
getChopsticks();
}
}else{//其他情況先搶右邊的筷子
if(rightChopsticks(tem)){//先搶右手邊的筷子
if(leftChopsticks(tem)){//如果獲得了右手邊的 去搶左手邊的筷子
eating();//如果獲得了兩只筷子 開始吃飯
freeLeftChopsticks(tem);//吃完了 釋放左手邊的筷子
freeRightChopsticks(tem);//釋放右手邊的筷子
}else{
freeRightChopsticks(tem);
System out println( 由于 +this getName()+ 無法獲得左手邊的筷子 所以他把已獲得的右手的筷子也釋放了! );
try {
this sleep( );
} catch (InterruptedException e) {
e printStackTrace();
}
getChopsticks();
}
}else{
System out println(this getName()+ 暫時無法獲取兩只筷子 準備休眠! );
try {
this sleep( );
} catch (InterruptedException e) {
e printStackTrace();
}
getChopsticks();
}
}
}
public boolean leftChopsticks(int tem){//獲取左手邊筷子
if(chopsticks[tem]== ){
chopsticks[tem]= ;
System out println(this getName()+ 左手邊筷子已獲得! );
return true;
}else{
System out println(this getName()+ 左手邊筷子已被哲學家 +(tem )+ 搶走! );
return false;
}
}
public boolean rightChopsticks(int tem){//獲取右手邊筷子
int i=(tem+ )% ;
if(chopsticks[i]== ){
chopsticks[i]= ;
System out println(this getName()+ 右手邊筷子已獲得! );
return true;
}else{
System out println(this getName()+ 右手邊筷子已被哲學家 +i+ 搶走! );
return false;
}
}
public void freeLeftChopsticks(int tem){//獲取左手邊筷子
chopsticks[tem]= ;
System out println(this getName()+ 左手邊筷子已釋放! );
}
public void freeRightChopsticks(int tem){//獲取右手邊筷子
int i=(tem+ )% ;
chopsticks[i]= ;
System out println(this getName()+ 右手邊筷子已釋放! );
}
public void eating(){//開始進餐
System out println( * +this getName()+ 兩只手都有了筷子 所以開始吃飯! );
}
/**
* 主函數(shù)
*/
public static void main(String[] args) {
for(int i= ; i ; i++){
new Scientist( 哲學家 +i) start();
}
}
lishixinzhi/Article/program/Java/hx/201311/25798
網(wǎng)頁題目:哲學家進餐java代碼 哲學家進餐問題3種代碼
文章鏈接:http://jinyejixie.com/article36/dodpppg.html
成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供ChatGPT、品牌網(wǎng)站建設(shè)、網(wǎng)站策劃、微信公眾號、域名注冊、品牌網(wǎng)站設(shè)計
聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請盡快告知,我們將會在第一時間刪除。文章觀點不代表本網(wǎng)站立場,如需處理請聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時需注明來源: 創(chuàng)新互聯(lián)