[英]What does it mean to return a value after calling wait()?
在下面的代碼中,我有一個關於調用wait()后會發生什么的問題。 在我的代碼中,我在調用wait()
后返回一個值,這實際上是做什么的? 我認為,調用wait()
掛起當前線程,但會發生什么變化值i
傳遞給addWorkItem(Integer i)
如果wait()
調用時沒有返回false? 您可以在生產者線程中看到,如果無法將其添加到deque中,則會將i
添加到重試緩沖區。 如果我不等待后返回false,確實值i
只是迷路了,或者是它仍然存在,一旦線程被喚醒?
import java.util.ArrayDeque;
import java.util.ArrayList;
import java.util.Deque;
import java.util.List;
public class ConsumerProducer2 {
private static int QUEUE_SIZE = 10;
private Deque<Integer> queue = new ArrayDeque<Integer>(QUEUE_SIZE);
public synchronized boolean addWorkItem(Integer i) {
while (queue.size() >= QUEUE_SIZE) {
try {
wait();
return false; // WHAT HAPPENS HERE?
} catch (InterruptedException ex) {}
}
queue.addLast(i);
notify();
return true;
}
public synchronized Integer getWork() {
while (queue.size() == 0) {
try {
wait();
return null; // WHAT HAPPENS HERE?
} catch (InterruptedException ex) {
}
}
Integer i = queue.removeFirst();
notify();
return i;
}
public static void main(String[] args) {
new ConsumerProducer2().go();
}
public void go() {
ConsumerThread ct = new ConsumerThread();
ct.start();
ConsumerThread ct2 = new ConsumerThread();
ct2.start();
ProducerThread pt = new ProducerThread();
pt.start();
}
class ConsumerThread extends Thread {
public void run() {
while(true) {
Integer work = getWork();
if (work == null) {
} else {
System.out.println("Thread: " + this.getId() + " received work: " + work);
}
}
}
}
class ProducerThread extends Thread {
private List<Integer> retryList = new ArrayList<Integer>();
public void run() {
while(true) {
Integer currWork;
if (retryList.size() == 0) {
currWork = (int) (Math.random() * 100);
} else {
currWork = retryList.remove(0);
System.out.println("Thread: " + this.getId() + " retrying old work: " + currWork);
}
if (!addWorkItem(currWork)) {
System.out.println("Thread: " + this.getId() + " could not add work (because buffer is probably full): " + currWork);
retryList.add(currWork);
} else {
System.out.println("Thread: " + this.getId() + " added work to queue: " + currWork);
}
}
}
}
}
讓生產者維護重試緩沖區確實使i值不會丟失,但這仍然不是編寫方法的好方法。
從while循環內部返回沒有意義。 你檢查隊列的大小,如果它已經達到最大值,你就等到你得到隊列大小改變的通知,然后莫名其妙地返回false(??)。 等待並沒有真正完成任何事情。
addWorkItem中的等待點是延遲線程,直到隊列有新值的空間。 你應該在循環中等待,當你退出等待時,你的線程重新獲取鎖並重新檢查條件(隊列大小>最大),看它是否可以添加項目。
一旦線程退出while循環,它就會持有鎖,它確保新項目的隊列中有足夠的空間(因為沒有其他線程可以做任何事情來改變隊列的大小,而這個線程有鎖定),它可以繼續並將值添加到隊列中。
您正在以非生產性的方式捕獲InterruptedException,因為您捕獲它,不必費心恢復中斷標志,並返回到while循環的頂部。 你應該使用中斷來退出等待並退出方法。 讓InterruptedException拋出這里會更有意義; 運行該方法的線程應該比這個對象更好地了解如何處理中斷。
您不應該假設等待僅在通知線程時返回,它可以在沒有通知的情況下返回。 這是在循環中調用wait的原因之一。
返工版本:
public synchronized boolean addWorkItem(Integer i) throws InterruptedException {
while (queue.size() >= QUEUE_SIZE) {
wait();
}
queue.addLast(i);
notify();
return true;
}
如果你想借口從這里返回false,那么如果隊列在一段時間內沒有為新條目騰出空間,那么你可以使方法返回false(在很多現實情況下,超時可能是一件好事):
public synchronized boolean addWorkItem(Integer i) throws InterruptedException {
final long maxWaitTime = 60L * 1000;
long totalWaitTime = 0;
while (queue.size() >= QUEUE_SIZE && totalWaitTime <= maxWaitTime) {
long waitStartTime = System.currentTimeMillis();
wait(maxWaitTime);
totalWaitTime += (System.currentTimeMillis() - waitStartTime);
}
if (queue.size() >= QUEUE_SIZE) {
return false;
}
queue.addLast(i);
notify();
return true;
}
這仍然會使用重試緩沖區(它上面的第一個版本根本不會執行),但可能不會像現在這樣多。
另一件事:你有生產者和消費者線程同時訪問它,並且兩種情況都會調用notify。 由於通知僅喚醒一個線程,因此線程可能會獲得與其無關的通知(因此通知的線程會喚醒,檢查其狀況並發現它仍然是假的,然后等待更多,而另一個線程,通知實際上很重要,從來沒有發現它)。 你可以用不同的方法解決問題
分配單獨的鎖,一個用於生產者,一個用於消費者,
減少傳遞給wait方法的超時,這樣你就不會依賴於獲得通知,或者
你可以使用notifyAll(性能較差但快速修復)。
看看這個 。
簡短的故事 :一個等待的線程可以被另一個呼叫通知喚醒。 所以在你的情況下,addWorkItem將在另一個線程調用notify()
之后調用wait()
的線程中返回false。
另外看看你的邏輯我認為你在隊列為空時試圖阻止消費者,並在有工作要做的時候喚醒它。 並且您希望生產者在隊列為空之前不要提供新的工作。 如果是這種情況,那么在等待之后調用return將關閉你的消費者/生產者,而不是讓他們盡可能地完成他們的工作。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.