这个多线程java代码中确实存在竞争条件吗?

时间:2013-04-21 18:20:23

标签: java multithreading synchronization race-condition producer-consumer

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

  1. 根据我的理解,只有在生产者决定不在队列中添加任何项目之后,才会在消费者上设置“isRunning”。因此,如果消费者线程将isRunning视为FALSE然后看到inputQueue为空,那么将来不可能有更多的东西被添加到队列中。 显而易见,我错了,错过了一些东西,因为没有人回答这个问题说这个问题的情景是不可能的。那么,有人可以解释一下这种竞争条件会导致这种竞争条件吗?

  2. 事实上,我看到了别的问题。例如,如果多个消费者线程看到生产者正在运行,并且说队列有一个项目,那么许多线程可能会进入被阻止的'take'。如果制作人现在STOPS,而一个线程就会出现'take', 其他线程永远被阻止在'take'上。有趣的是,没有人回答这个问题也指出了这个问题。所以,我对此的理解也可能有问题?!

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

    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;
    }
    

2 个答案:

答案 0 :(得分:1)

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

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

而不是

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

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

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

答案 1 :(得分:0)

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

对于我,我会创建一个新的同步类,它聚合队列和isRunning变量,以便更改isRunning会导致take()中的异常,从而表示工作结束。