我需要編寫一個java程序,但我需要一些建議,然後才能自行開始。作爲監視器的Java類
程序我會寫是要做到以下幾點:
模擬商店花費甜甜圈先進的訂單
商店不會採取進一步的命令,一旦5000個甜甜圈有已訂購
好吧,我是一種卡住的想法,如果我應該寫的Java類作爲監視器還是應該使用Java-Semaphore類?
請指教我。謝謝您的幫助。
我需要編寫一個java程序,但我需要一些建議,然後才能自行開始。作爲監視器的Java類
程序我會寫是要做到以下幾點:
模擬商店花費甜甜圈先進的訂單
商店不會採取進一步的命令,一旦5000個甜甜圈有已訂購
好吧,我是一種卡住的想法,如果我應該寫的Java類作爲監視器還是應該使用Java-Semaphore類?
請指教我。謝謝您的幫助。
任何Java對象可以作爲顯示器通過等待工作/通知從Object
繼承的方法:
Object monitor = new Object();
// thread 1
synchronized(monitor) {
monitor.wait();
}
// thread 2
synchronized(monitor) {
monitor.notify();
}
只要確保握住顯示器對象的鎖調用這些方法時(不擔心wait
,該鎖被自動釋放以允許其他線程獲取它)。通過這種方式,您可以在線程間傳送信號。
在我看來,你似乎正在實施一個有界的生產者 - 消費者隊列。在這種情況下:
wait
並進入休眠狀態。notify
來喚醒消費者,如果它正在等待。notify
來喚醒生產者。wait
並進入睡眠狀態。對於更加簡化的方法,請在BlockingQueue的各種實施中進行循環,以提供上述功能!
就像都鐸王朝寫的,你可以使用任何對象作爲監視器來進行通用鎖定和同步。
但是,如果您有任何時候只能處理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
}
在我看來,該這個練習的核心是以線程安全和原子的方式更新一個計數器(所採取的命令的數量)。如果實施不當,您的店鋪可能會因爲錯過更新而導致超過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);
,另一個線程可能會增加調用get
和set
,所以此更新將失去通過使整個遞增操作的原子 - 因爲它在synchronized塊 - 不能出現這種情況
在實踐中,我可能會使用一個AtomicInteger代替,這就是生活。基本上是圍繞int
的包裝,以允許原子查詢和更新,就像DonutShop
分類以上。它還具有這樣的優點,即它在減少獨佔阻止方面更爲高效,而且它是標準庫的一部分,因此與其他開發人員相比,您會更熟悉自己編寫的類。
就正確性而言,任何一項都足夠了。
謝謝你的幫助Andrzej。非常感謝。 – JasonMayhem 2012-04-23 10:40:05
感謝您的快速響應。好的如何用Java-CyclicBarrier類書寫這是更好的選擇呢? – JasonMayhem 2012-04-23 10:14:30
@JasonMayhem:實際上,'CyclicBarrier'構造似乎更適合主工模式(即做一些工作的線程團隊,然後等待彼此完成),而不是生產者 - 消費者。對於這個場景,你可以使用'BlockingQueue'的實現。 – Tudor 2012-04-23 10:17:52
謝謝都鐸王朝。我從BlockingQueue鏈接中猜測,只需編寫類作爲生產者和消費者即可輕鬆完成此任務。所以我可以跳過顯示器執行權限? – JasonMayhem 2012-04-23 10:26:09