1

我在这个问题中看到了一段我无法理解的代码片段(很可能是因为我是该领域的初学者)。这个问题谈到了“一个明显的竞争条件,有时生产者会完成,发出信号,而 ConsumerWorkers 会在消费队列中的所有内容之前停止。”

  1. 据我了解,只有在生产者决定不再在队列中添加项目后,才会在消费者身上设置“isRunning”。因此,如果消费者线程将 isRunning 视为 FALSE,然后看到 inputQueue 为空,那么将来就不可能再将任何东西添加到队列中。显然,我错了并且遗漏了一些东西,因为没有人回答这个问题,说这个问题的场景是不可能的。那么,有人可以解释一下导致这种竞争状况的事件顺序吗?

  2. 事实上,我看到了其他问题。例如,如果多个消费者线程看到生产者正在运行,并说队列有一个项目,那么许多线程可能会进入阻塞的“获取”。如果生产者现在停止,虽然一个线程会从“take”中出来,但其他线程将永远被阻塞在“take”上。有趣的是,回答这个问题的人也没有指出这个问题。所以,我对此的理解也可能是错误的?!

我不想在那个问题中添加这个作为评论,因为这是一个老问题,我的疑问可能永远不会得到回答!我在此处复制/放置该问题的代码以供快速参考。

public class ConsumerWorker implements Runnable{

private BlockingQueue<Produced> inputQueue;
private volatile boolean isRunning = true;

public ConsumerWorker(BlockingQueue<Produced> inputQueue) {
    this.inputQueue = inputQueue;
}

@Override
public void run() {
    //worker loop keeps taking en element from the queue as long as the producer is still running or as 
    //long as the queue is not empty:
    while(isRunning || !inputQueue.isEmpty()) {
        System.out.println("Consumer "+Thread.currentThread().getName()+" START");
        try {
            Object queueElement = inputQueue.take();
            //process queueElement
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

//this is used to signal from the main thread that he producer has finished adding stuff to the queue
public void setRunning(boolean isRunning) {
    this.isRunning = isRunning;
}
4

2 回答 2

1

我认为原始问题的 OP 可能意味着

while(isRunning && !inputQueue.isEmpty()) 

而不是

while(isRunning || !inputQueue.isEmpty())

前者清楚地产生了原始海报(*)描述的问题,而后者确实存在您在第二点中描述的问题。那里有一个简单的疏忽,但现在我们可以注意到这两种方法都是不正确的。

(*) 并以某种方式假设队列永远不会为空。

于 2013-04-21T19:03:59.577 回答
0

你在这两个问题上都是正确的。是&&的是正确的,||不是。至于第二个问题,答案是使用poison pill或超时,两种方式都可以解决问题。

至于我,我将创建新的同步类,它聚合队列和isRunning变量,以便更改isRunning会导致异常,take()从而发出工作结束的信号。

于 2013-04-22T14:10:15.283 回答