我正在嘗試在 Java 中創建執行緒安全佇列。我遇到過這個例子:
class ProducerConsumer<T> {
private static final int BUFFER_MAX_SIZE = 42;
private List<T> buffer = new LinkedList<>();
synchronized void produce(T value) throws InterruptedException {
while (buffer.size() == BUFFER_MAX_SIZE) {
wait();
}
buffer.add(value);
notify();
}
synchronized T consume() throws InterruptedException {
while (buffer.size() == 0) {
wait();
}
T result = buffer.remove(0);
notify();
return result;
}
}
我是 Java 新手。根據我的理解,這兩個“同步”關鍵字可以防止每個方法內部發生爭用,但在同時呼叫這兩個方法時不會。例如執行緒 P 呼叫生產,鎖定方法,執行緒 C 呼叫消費,鎖定其他方法,然后一個嘗試從串列中提取元素,另一個嘗試插入元素,執行緒例外出現。
我的問題:這個例子壞了嗎?
或者也許我錯過了一些東西,沒關系。
uj5u.com熱心網友回復:
JLS, §17.1對機制非常明確:
...
阿
synchronized法(§8.4.3.6)自動執行,當它被呼叫的鎖定動作; 它的主體在鎖定操作成功完成之前不會執行。如果該方法是一個實體方法,它會鎖定與呼叫它的實體相關聯的監視器(即,this在方法主體執行期間將被稱為的物件)。如果方法是static,則鎖定與Class表示定義該方法的類的物件關聯的監視器。如果方法體的執行完成,無論是正常的還是突然的,都會在同一個監視器上自動執行解鎖操作。...
因此,可以保證在一個物件上的某個時間點至多有一個執行緒正在執行 produce(...)或consume()。在某個時間點,一個執行緒produce(...)在一個物件上執行而另一個執行緒consume()在同一個物件上執行是不可能的。
呼叫wait()inconsume()釋放內在鎖并阻止執行。呼叫notify()inproduce(...)釋放內在鎖并通知一個wait()ing 執行緒(如果有),因此它可以鎖定內在鎖并繼續執行。
我建議改變的事情是:
private List<T> buffer另外宣告為final- 呼叫
notifyAll(),而不是notify()為了喚醒所有等待的執行緒(他們仍然會按順序執行,詳見這個問題由謝爾蓋Mikhanov及答案)
轉載請註明出處,本文鏈接:https://www.uj5u.com/yidong/344093.html
上一篇:我有一個檢測臟話的minecraft插件。玩家詛咒時如何執行命令?
下一篇:Maven沒有運行JUnit測驗
