簡體   English   中英

調用wait()后返回值是什么意思?

[英]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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM