2012-06-21 19 views
7

我必須用Java信號量來解決這個問題,但我不知道如何,也找不到任何相關的Java資料。這是怎麼回事:
Java男女皆宜的浴室

有各種線程:男人和女人。兩者都想使用相同的資源,其數量是BATHROOM_SIZE。 5規則:

  1. 每個線程,在信號需要使用資源後,都應該等到他能夠使用它。
  2. 當多於BATHOOM_SIZE線程同時使用資源時,防止出現這種情況。
  3. 防止女人和男人在同一時間使用澡堂。
  4. 線程應該同時使用資源。如果有一個類型的線程很多,則BATHROOM_SIZE線程應該使用資源。
  5. 預防飢餓。

結果

Works爲:

1woman,1man,5women,5men

失敗爲:

5women1men,5men1women,2men2women,5men5women。

自從星期一起,我一直在努力讓它工作,現在我已經用完了想法。

代碼

所以,我的任務是寫Bathroom.java類,它實現BathroomInterface

public interface BathroomInterface { 

    public static final int BATHROOM_SIZE = 3; //3 is just example 
    void manEnter(); 
    void manExit(); 
    void womanEnter(); 
    void womanExit(); 
} 

在系統中有許多男人和女人螺紋,這樣工作的:

for(int i = 0; i < n; i++) { 
    bathroom.manEnter(); 
    //uses bathroom random amount of time 
    bathroom.manExit(); 
} 

for(int i = 0; i < m; i++) { 
    bathroom.womanEnter(); 
    //uses bathroom random amount of time 
    bathroom.womanExit(); 
} 

我也有計劃Bathroom.java類,我不得不延長:

import java.util.concurrent.Semaphore; 

public class Bathroom implements BathroomInterface { 


    private Semaphore mutex = new Semaphore(1, true); 

    public void womanEnter() { 
     mutex.acquireUninterruptibly(); 
    } 

    public void womanExit() { 
     mutex.release(); 
    } 

    public void manEnter() { 
     mutex.acquireUninterruptibly();   
    } 

    public void manExit() { 
     mutex.release(); 
    } 
} 

這是我迄今所取得:

import java.util.concurrent.Semaphore; 

public class Bathroom implements BathroomInterface { 
    int manW=0, manU=0, womanW=0, womanU=0; //*U-using, *W-waiting 
    private Semaphore mutex = new Semaphore(1, false); 

    public void womanEnter() { 
     womanW++; 
     StateChange(); 
    } 

    public void womanExit() { 
     womanU--; 
     mutex.release(); 
     StateChange(); 
    } 

    public void manEnter(){ 
     manW++; 
     StateChange(); 
    } 

    public void manExit() { 
     manU--; 
     mutex.release(); 
     StateChange(); 
    } 

    void StateChange() { 
     if(womanU==0 && manU==0) { 
      if(manW>womanW) { 
       while(manW>0 && manU<BATHROOM_SIZE) { 
        manW--; 
        manU++; 
        mutex.acquireUninterruptibly(); 
       } 
      } 
      else { 
       while(womanW>0 && womanU<BATHROOM_SIZE) { 
        womanW--; 
        womanU++; 
        mutex.acquireUninterruptibly(); 
       } 
      } 
     } 
     if(womanU==0 && manU<BATHROOM_SIZE) { 
      while(manW>0 && manU<BATHROOM_SIZE) { 
       manW--; 
       manU++; 
       mutex.acquireUninterruptibly(); 
      } 
     } 
     if(manU==0 && womanU<BATHROOM_SIZE) { 
      while(womanW>0 && womanU<BATHROOM_SIZE) { 
       womanW--; 
       womanU++; 
       mutex.acquireUninterruptibly(); 
      } 
     } 
    } 
} 
+4

「失敗」的意思是什麼?它會死鎖,崩潰,凍結,拋出異常,...?請記住,您提供的細節越多,獲得的幫助就越多。 –

+2

好的,我有一些問題。如果你的浴室有更多的容量,爲什麼你使用size = 1的信號量?信號量是爲了自動管理多個相同類型的資源而創建的。 – Th0rndike

+1

只是很搞笑! –

回答

5

其實這個練習是利用顯示器進行,而不是一個信號。你所做的大部分都很好,你錯過了這些條件。所以,在你的浴室類中,聲明:

鎖:

private Lock lock = new ReentrantLock(); 

2個條件或隊列,連接到您的鎖:

private Condition womenWaitingQueue = lock.newCondition(); 
private Condition menWaitingQueue = lock.newCondition(); 

2櫃檯知道有多少人在等待,並2知道有多少正在使用:

private int womenWaitingN = 0; 
private int menWaitingN = 0; 
private int womenUsingN = 0; 
private int menUsingN = 0; 

,當然還有,資源的數量:

private final int BATHROOM_CAPACITY = 5; 
private int free_resources = BATHROOM_CAPACITY; 

所有4個功能都在這裏,但因爲功課標籤去除

這裏最重要的是防止飢餓,不容許任何人,以是否有婦女在等待進入浴室,反之亦然。

所以,條件是,如果一個男人想進入浴室,它必須檢查浴室是否至少有一個空閒位置(使用免費資源)以及浴室中是否有女性(使用womenUsingN)。如果有任何的這2個條件不滿足,男方必須等待(使用menWaitingQueue):

menWaitingQueue.await(); 

當一個人離開浴室,它有,檢查是否有等待的女人(womenWaitingN),如果有是,他們得到通知:

womanWaitingQueue.signal(); 

因爲menUsingN計數器,這個信號的女性將無法進入,直到有浴室裏沒有人。如果沒有女性在等待,那麼可以發信號通知男人進入浴室。這防止了飢餓,因爲優先考慮異性(如果等待)。

最後一件事是,每個函數都必須在每個進入/退出函數的開始/結束時鎖定/解鎖

lock.lock(); 
lock.unlock(); 

我覺得有了這個新的信息,你就可以獨立完成這些功能。祝你好運!

+0

+1飢餓預防實際上是問題中最有趣的方面,因爲沒有單一的正確答案。通常情況下,你會發現一些像交通燈一樣工作並定期切換優先級的東西。我喜歡你的轉機出口的想法:浴室是空的,充滿了等待的女人。第一個退出觸發開關,所以在浴室清空後,它充滿了等待的人,首先退出觸發它。這是公平性和性能的完美結合,並且避免了「在空曠的道路上等待紅燈」的異常交通燈經常出現的情況。 – wallenborn

2

我認爲你與整個mutex.acquire和mutex.release語義糾纏在一起,尤其是互斥體實際上應該保護的東西。讓我試着簡化這個問題,給你提示如何解決這個問題。

您被要求實現一個併發對象,它比簡單的信號量更復雜,有兩個客戶端類和飢餓預防。我不會爲你做的,但我要告訴你一個簡單的信號怎麼看起來像在-的Java6天前:

public class Resource { 

    private int numClients = 0; 
    private final int maxClients; 

    public Resource(int maxClients) { 
     this.maxClients = maxClients; 
    } 

    public synchronized void acquire() { 
     while (!clientCanAcquire()) { 
      try { 
       wait(); 
      } catch (InterruptedException e) { 
      } 
     } 
     ++numClients; 
     printState(); 
    } 

    public synchronized void release() { 
     --numClients; 
     printState(); 
     notify(); 
    } 

    private boolean clientCanAcquire() { 
     return numClients < maxClients; 
    } 

    private void printState() { 
     System.out.println("Resource is currently acquired by " + numClients 
       + " clients"); 
    } 
} 

客戶端可以訪問此如下:

import java.util.Random; 

public class Client implements Runnable { 

    private Resource resource; 
    private Random rnd = new Random(); 

    public Client(Resource resource) { 
     this.resource = resource; 
    } 

    public void run() { 
     try { 
      Thread.sleep(rnd.nextInt(1000)); 
      resource.acquire(); 
      Thread.sleep(rnd.nextInt(1000)); 
      resource.release(); 
     } catch (InterruptedException e) { 
     } 
    } 
} 

並能帶動整個事情是這樣的最簡單的應用:

public class App { 

    public static void main(String[] arg) { 

     Resource r = new Resource(3); 
     for (int i = 0; i < 10; i++) { 
      Thread client = new Thread(new Client(r)); 
      client.start(); 
     } 
    } 
} 

資源存儲需要確定當客戶端在內部變量訪問這些信息。在多線程應用程序中,必須同步訪問這些變量。這裏顯示的是要做到這一點最簡單的方法,但你也可以說

private Object mutex = new Object(); 

然後

synchronized (mutex) { } 

或任何其他類型的互斥鎖。

你的問題比簡單的普通信號量更復雜,但底層邏輯應該非常相似。

+0

很好的例子。我認爲這與我的答案用戶會很高興。 – Th0rndike

0

@ Th0rndike好吧,我跟着你的提示,寫某事像這樣:

import java.util.concurrent.Semaphore; 
import java.util.concurrent.locks.*; 

public class Bathroom implements BathroomInterface { 
    private Semaphore mutex = new Semaphore(1, false); 

    private Lock lock = new ReentrantLock(); 
    private Condition womenWaitingQueue = lock.newCondition(); 
    private Condition menWaitingQueue = lock.newCondition(); 

    private int womenWaitingN = 0; 
    private int menWaitingN = 0; 
    private int womenUsingN = 0; 
    private int menUsingN = 0; 

    private int free_res = BATHROOM_SIZE; 

    public void womanEnter() { 
     lock.lock(); 
     if(free_res>0 && menUsingN==0) { 
      womenUsingN++; 
      free_res--; 
      mutex.acquireUninterruptibly(); 
     } 
     else 
      try { 
       womenWaitingQueue.await(); 
      } 
     catch(Exception e) { 
      System.out.println("E!"); 
     } 
     lock.unlock(); 
    } 

    public void womanExit() { 
     lock.lock(); 
     womenUsingN--; 
     free_res++; 
     mutex.release(); 
     if(menWaitingN>0) { 
      try { 
       menWaitingQueue.signal(); 
      } 
      catch(Exception e) { 
       System.out.println("E!"); 
      } 
     } 
     lock.unlock(); 
    } 

    public void manEnter() { 
     lock.lock(); 
     menUsingN++; 
     free_res--; 
     if(free_res>0 && womenUsingN==0) { 
      mutex.acquireUninterruptibly(); 
     } 
     else 
      try { 
       menWaitingQueue.await(); 
      } 
     catch(Exception e) { 
      System.out.println("E!"); 
     } 
     lock.unlock();  
    } 

    public void manExit() { 
     lock.lock(); 
     menUsingN--; 
     free_res++; 
     mutex.release(); 
     if(womenWaitingN>0) { 
      try { 
       womenWaitingQueue.signal(); 
      } 
      catch(Exception e) { 
       System.out.println("E!"); 
      } 
     } 
     lock.unlock(); 
    } 
} 

但是當我把它提交給自動程序檢查,在1man和1woman測試一切正常,但在休息,它返回「實時超出」錯誤。如果我刪除lock.lock()/ unlock(),「實時超時」錯誤將更改爲「錯誤答案」。

+0

什麼是實時超時? – Th0rndike

+0

你不需要信號量了。另外,當增加一個女人到隊列中時,你不會遞增womanWaitingN計數器(男人也一樣)。你錯過的另一件事就是等待:如果一個女人有信號,進入浴室的條件必須再次檢查才允許她們進入,特別是因爲如果浴室裏有男人,我們不能讓女人進入,他們可以在這種情況下得到信號,所以,必須有一段時間的循環,如果條件不符合,那麼該女人又會排隊等候。 – Th0rndike