【问题标题】:Terminating out of Producer Consumer setup using wait and notify使用等待和通知终止生产者消费者设置
【发布时间】:2015-02-02 01:46:02
【问题描述】:

请在下面找到消费者生产者代码:

// 生产者

    public boolean busy = false;
    while (rst != null && rst.next()) {
        while (queue.size() == 10) {
            synchronized (queue) {
                try {
                    log.debug("Queue is full, waiting");
                    queue.wait();
                } catch (InterruptedException ex) {
                    ex.printStackTrace();
                }
            }
        }

        synchronized (queue) {
            queue.add(/* add item to queue */);
            busy = true;
            queue.notifyAll();
        }
    }

// 消费者

    try {
        while (!busy) {
            while (queue.isEmpty()) {
                synchronized (queue) {
                    try {
                        log.debug("Queue is empty, waiting");
                        queue.wait();
                    } catch (InterruptedException ex) {
                        ex.getMessage();
                    }
                }
            }

            synchronized (queue) {
                item = queue.remove();
                log.debug("Consumed item" + ++count + " :" + item);
                busy = false;
                queue.notifyAll();
            }
        }

在我的生产者代码 sn-p 中,我已经同步了我用来添加元素的队列(链接阻塞队列),并使全局布尔变量忙到 true 并通知消费者。一旦队列大小为 10,生产者释放对象锁并进入等待状态。 对于我的消费者来说,一旦全局标志繁忙为真,消费者就会消耗元素并将标志变为假。 元素被适当地生产和消费。但我的代码没有从生产者消费者循环中终止,要执行的最终语句是“队列为空,等待”。 请告诉我如何修改我的代码和终止条件以退出循环。

【问题讨论】:

  • 不要忽略InterruptedException,而是将其作为停止信号。这意味着您不需要自己的busy 标志,因为系统提供了一个供您使用。请参阅Brian Goetz: Dealing with InterruptedException,尤其是“实施可取消任务”部分。

标签: java multithreading concurrency thread-safety producer-consumer


【解决方案1】:

您的代码被破坏的方式太多,很难决定从哪里开始。起初,您的消费者完全封闭在while(!busy){ 循环中,因此一旦busy 变为true,它将退出循环而不是开始消费项目。但是由于您在任何同步机制之外访问busy 变量,因此无法保证该线程将看到另一个线程写入的true 值。在这一点上,当wait 返回时,您的消费者不会真正检查队列的状态,而只是假设有项目(这不能保证,请阅读“spurios 唤醒”等),这“有助于”Object.wait 的文档解释如何正确等待。

但正确同步失败的次数更多。在你说的制片人中

while(queue.size() == 10){
    synchronized(queue){
        …

换句话说,您正在通过调用size() 访问队列而没有正确同步。

另一个问题是您的异常处理:

catch(InterruptedException ex)
{
    ex.getMessage();
}

调用getMessage 但忽略结果就像根本不调用它。你应该在这里添加一个真实的动作。即使是简单的print 声明也比这更好。

此外,只要您只有一个生产者和一个消费者,将等待部分和生产/消费部分分成两个不同的synchronized 块可能会起作用,但是一旦您有更多线程,它就会中断,因为在这两者之间两个synchronized 块,队列的状态可能会再次改变。


正确操作并不难,只需简化您的代码:

//Producer
public volatile boolean producerDone = false;
while( /* can produce more items */ ) {
    Item item=produceItem();
    synchronized(queue) {
        while(queue.size() == 10) try {
           log.debug("Queue is full, waiting");
           queue.wait();
        } catch(InterruptedException ex) {
            ex.printStackTrace();
        }
        queue.add(item);
        queue.notifyAll();
    }
}
producerDone=true;

 

//Consumer
while(!producerDone) {
    Item item;
    synchronized(queue) {
        while(queue.isEmpty()) try {
            log.debug("Queue is empty, waiting");
            queue.wait();
        } catch(InterruptedException ex) {
            ex.printStackTrace();
        }
        item = queue.remove();
        queue.notifyAll();
    }
    processItem(item);
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-04-09
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多