为什么在以下阻塞队列示例中调用notify()的顺序很重要?

时间:2013-09-16 05:49:58

标签: java multithreading

我为Prod-Cons问题编写了一个简单的阻塞队列示例。以下示例不起作用;除非我在等待线程上使用notify交换enqueue / dequeue逻辑的add / remove部分。在BlockingQueue的任何实现中,我都找不到任何关于此行为的明确解释。在enqueue部分,添加元素然后通知不应该是正确的吗?通过这种方式,我可以保证当Consumer线程运行时,它应该有一个元素给消费者,并且不会返回null。请解释一下。

import java.util.LinkedList;
import java.util.Queue;

public class BlockingQueueCustom<T> {

    private int size = 10;
    private Queue<T> queue = new LinkedList<T>();

    public BlockingQueueCustom(int s) {
        this.size = s;
    }

    public synchronized void enqueue(T element) throws InterruptedException {
        while (queue.size() == size) {
            wait();
        }
        queue.add(element); //Comment this part to make it work
        if (queue.size() == 0) {
            this.notifyAll();
        }
        //queue.add(element); Uncommenting this will make it work
    }

    public synchronized T dequeue() throws InterruptedException {
        while (queue.size() == 0) {
            this.wait();
        }
        T element = queue.remove(); //Comment this part to make it work
        if (queue.size() == size) {
            this.notifyAll();
        }
            return element; //Comment this part to make it work
        //return queue.remove(); Uncommenting this will make it work
    }
} 

1 个答案:

答案 0 :(得分:8)

  

在enqueue部分,添加元素然后通知不应该是正确的吗?

那部分并不重要,因为你处于同步方法中 - 其他线程无论如何都要运行,直到你离开enqueue方法。但是,确实size()的测试很重要。看这里:

if (queue.size() == 0)

如果您刚刚添加元素,您认为这是真的吗?您可以检查它是否为1,这意味着之前添加了必须为0的元素。或者您可以保留一个单独的变量:

boolean shouldNotify = queue.size() == 0;
queue.add(element);
if (shouldNotify) {
    this.notifyAll();
}