[英]Implementing Producer Consumer problem using lock on list
這是作業的生產者消費者模式的一種實現。 下面的實現有什么問題。 這會導致死鎖。 我無法理解出了什么問題。
我有一個共享隊列
我在同一鎖上同步生產者和消費者
private static volatile Queue<Integer> BUFFER = new LinkedList<>();
private static int COUNT = 0;
private static final int SIZE = 1;
public static void main(String[] args) {
new Thread(() -> {
while (true) {
while (BUFFER.size() == SIZE) {
synchronized (BUFFER) {
try {
System.out.println("Producer waiting");
BUFFER.wait();
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
synchronized (BUFFER) {
System.out.println("Producer added : " + COUNT);
BUFFER.offer(COUNT++);
System.out.println("Producer notify");
BUFFER.notify();
}
try {
Thread.sleep(500l);
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}).start();
new Thread(() -> {
while (true) {
while (BUFFER.isEmpty()) {
synchronized (BUFFER) {
try {
System.out.println("Consumer waiting");
BUFFER.wait();
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
synchronized (BUFFER) {
System.out.println("Consumer consumed : "+ BUFFER.poll());
BUFFER.notify();
}
try {
Thread.sleep(500l);
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}).start();
}
}
一段時間后,此代碼將導致死鎖。
Producer added : 0
Producer notify
Consumer consumed : 0
Consumer waiting
Producer added : 1
Producer notify
Consumer consumed : 1
Producer added : 2
Producer notify
Consumer waiting
Producer waiting
您的代碼容易丟失通知 。 這是可能發生的情況:
BUFFER.notify()
。 BUFFER.wait()
(因為緩沖區在檢查時為空)。 BUFFER.size() == 1
)。 BUFFER.wait()
現在,每個線程都在等待對方做某事:死鎖!
步驟2中的通知丟失。 如果另一個線程尚未等待,則BUFFER.notify()
根本不執行任何操作。
實際上,只有一種正確的方法可以使用wait()
和notify()
。 您可以在這里閱讀有關內容: https : //docs.oracle.com/javase/tutorial/essential/concurrency/guardmeth.html
為生產者消費者使用notify
不是正確的方法。 如果在調用notify()
時實際上沒有人在等待該通知,則notify()
將丟失。
而不是使用wait()
和notify()
,應該使用semaphore
。
共享semaphore
可以由任何線程釋放和獲取,並且是在這種類型的線程間通信中使用的正確工具。
在這種情況下,使用者將從隊列中消費並release()
semaphore
。 生產者將acquire()
信號量並將某些內容推入隊列。 如果隊列已滿,則生產者將在嘗試獲取semaphore
直到消費者清空隊列。 與您基本上在這里使用的條件變量不同,通過使用wait()
和notify()
, semaphore
保持狀態。
在Udemy的“ Java多線程,並發和性能優化 ”課程中,所有有關綁定隊列和未綁定隊列的示例都進行了深入討論。
它說明了何時使用條件變量以及何時以及如何使用信號量。
希望對您有所幫助
下面的實現有什么問題。 這會導致死鎖。 我無法理解出了什么問題。
while (BUFFER.isEmpty()) {
synchronized (BUFFER) {
你的代碼是接近,但synchronized
關鍵字必須包括在這里while循環為它工作,否則由@SolomonSlow所列舉它將從競爭條件受到影響。 這不是並發集合,盡管您將其標記為volatile
但不能保證isEmpty()
方法將返回true,可能會向列表中添加元素,然后使用者進入synchronized
塊。 您需要確保測試和等待發生在同一鎖中。
一旦你移動synchronized
關鍵字,可以去除volatile
則由於所有訪問BUFFER
是內部synchronized
。
synchronized (BUFFER) {
while (BUFFER.size() == SIZE) {
...
synchronized (BUFFER) {
while (BUFFER.isEmpty()) {
通過將同步移到兩個同時,您的代碼似乎對我有用。
其他一些評論:
System.out.println()
和notify()
調用包含在原始synchronized
。 那里不需要2個街區。 e.printStackTrace();
和TODO。 Exception
而應使其盡可能地精細。 catch InterruptedException
。 捕獲InterruptedException
,應根據策略始終重新中斷線程。
} catch (InterruptedException ie) { Thread.currentThread().interrupt(); // now handle the interrupt by quitting the thread or something }
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.