2012-04-23 72 views
3

我需要編寫一個java程序,但我需要一些建議,然後才能自行開始。作爲監視器的Java類

程序我會寫是要做到以下幾點:

  • 模擬商店花費甜甜圈先進的訂單

  • 商店不會採取進一步的命令,一旦5000個甜甜圈有已訂購

好吧,我是一種卡住的想法,如果我應該寫的Java類作爲監視器還是應該使用Java-Semaphore類?

請指教我。謝謝您的幫助。

回答

3

任何Java對象可以作爲顯示器通過等待工作/通知從Object繼承的方法:

Object monitor = new Object(); 

// thread 1  
synchronized(monitor) { 
    monitor.wait(); 
} 

// thread 2 
synchronized(monitor) { 
    monitor.notify(); 
} 

只要確保握住顯示器對象的鎖調用這些方法時(不擔心wait,該鎖被自動釋放以允許其他線程獲取它)。通過這種方式,您可以在線程間傳送信號。

在我看來,你似乎正在實施一個有界的生產者 - 消費者隊列。在這種情況下:

  1. 製作人將繼續將項目放入共享隊列中。
  2. 如果隊列大小達到5000,它將在共享監視器上調用wait並進入休眠狀態。
  3. 當它放置一個項目時,它將在顯示器上調用notify來喚醒消費者,如果它正在等待。
  4. 消費者將繼續從隊列中取出物品。
  5. 當它需要一個項目時,它會在顯示器上調用notify來喚醒生產者。
  6. 如果隊列大小達到0,則消費者呼叫wait並進入睡眠狀態。

對於更加簡化的方法,請在BlockingQueue的各種實施中進行循環,以提供上述功能!

+0

感謝您的快速響應。好的如何用Java-CyclicBarrier類書寫這是更好的選擇呢? – JasonMayhem 2012-04-23 10:14:30

+0

@JasonMayhem:實際上,'CyclicBarrier'構造似乎更適合主工模式(即做一些工作的線程團隊,然後等待彼此完成),而不是生產者 - 消費者。對於這個場景,你可以使用'BlockingQueue'的實現。 – Tudor 2012-04-23 10:17:52

+0

謝謝都鐸王朝。我從BlockingQueue鏈接中猜測,只需編寫類作爲生產者和消費者即可輕鬆完成此任務。所以我可以跳過顯示器執行權限? – JasonMayhem 2012-04-23 10:26:09

0

就像都鐸王朝寫的,你可以使用任何對象作爲監視器來進行通用鎖定和同步。

但是,如果您有任何時候只能處理x個訂單(對您的情況x = 5000)的要求,則可以使用java.util.concurrent.Semaphore類。它的使用情況下,你只能有固定的正在運行的作業數量特別製作 - 它被稱爲許可證Semaphore

的術語如果您立即做處理,你可以去

private Semaphore semaphore = new Semaphore(5000); 

public void process(Order order) 
{ 
    if (semaphore.tryAcquire()) 
    { 
     try 
     { 
      //do your processing here 
     } 
     finally 
     { 
      semaphore.release(); 
     } 
    } 
    else 
    { 
     throw new IllegalStateException("can't take more orders"); 
    } 
} 

如果如果需要做的更多(所需的人力投入,啓動另一個線程/進程等),你需要添加回調時處理過,如:

private Semaphore semaphore = new Semaphore(5000); 

public void process(Order order) 
{ 
    if (semaphore.tryAcquire()) 
    { 
     //start a new job to process order 
    } 
    else 
    { 
     throw new IllegalStateException("can't take more orders"); 
    } 
} 

//call this from the job you started, once it is finished 
public void processingFinished(Order order) 
{ 
    semaphore.release(); 
    //any other post-processing for that order 
} 
1

在我看來,該這個練習的核心是以線程安全和原子的方式更新一個計數器(所採取的命令的數量)。如果實施不當,您的店鋪可能會因爲錯過更新而導致超過5000個預購單,並且可能會看到櫃檯陳舊值不同的線程。

原子地更新計數器的最簡單的方法是使用​​方法來獲取和增加它:

class DonutShop { 

    private int ordersTaken = 0; 

    public synchronized int getOrdersTaken() { 
     return ordersTaken; 
    } 

    public synchronized void increaseOrdersBy(int n) { 
     ordersTaken += n; 
    } 

    // Other methods here 
} 

synchronized methods意味着只有一個線程可以在任何時候被調用這兩種方法(和它們還提供一個內存屏障,以確保不同的線程看到相同的值,而不是本地緩存的可能過時的值)。這確保了應用程序中所有線程的計數器的一致視圖。 (請注意,我沒有一個「set」方法,而是一個「增量」方法。「set」的問題是如果客戶端必須調用shop.set(shop.get() + 1);,另一個線程可能會增加調用getset,所以此更新將失去通過使整個遞增操作的原子 - 因爲它在synchronized塊 - 不能出現這種情況


在實踐中,我可能會使用一個AtomicInteger代替,這就是生活。基本上是圍繞int的包裝,以允許原子查詢和更新,就像DonutShop分類以上。它還具有這樣的優點,即它在減少獨佔阻止方面更爲高效,而且它是標準庫的一部分,因此與其他開發人員相比,您會更熟悉自己編寫的類。

就正確性而言,任何一項都足夠了。

+0

謝謝你的幫助Andrzej。非常感謝。 – JasonMayhem 2012-04-23 10:40:05