线程中生产者消费者的误区

Producer Consumer Misunderstanding in Threading

我希望 ProducerThread 生成最多 10 的随机值,然后期望 ConsumerThread 消费 Queue 的这些值。 Producer 在某处生成多次添加值。我有一个概念,当我们在一个对象上调用 notify 时,Thread 会释放锁并给等待更新的 Thread 机会。

这是代码,请指正我的理解。

public class ProducerThread extends Thread {

    Queue<Integer> values;

    ProducerThread(Queue<Integer> values) {
        this.values = values;
    }

    public void run() {
        while(true) {
            synchronized(values) {
                double totalValues = Math.random()*10;
                System.out.println("Going to populate total values:" + totalValues);

                for (int i = 1; i <= totalValues; i++) {
                    values.add(i);
                    System.out.println("Value updated: " + i);
                    try {
                        Thread.sleep(1000);
                    } catch (InterruptedException e) {
                        // TODO Auto-generated catch block
                        e.printStackTrace();
                    }
                }
                values.notify();
            }
        }
    }

}



public class ConsumerThread extends Thread {
    Queue<Integer> values;

    ConsumerThread(Queue<Integer> values) {
        this.values = values;
    }

    @Override
    public void run() {
        while(true) {
            synchronized (values) {

                try {
                    // Consumer Thread waits until values are populated by Producer Thread
                    if(values.isEmpty()) {
                        values.wait();
                    }

                    Iterator<Integer> iterateValues = values.iterator();
                    System.out.println("Going to consume values: " + values.size());
                    while (iterateValues.hasNext()) {
                        Integer removedValue = iterateValues.next();
                        System.out.println("Value deleted: " + removedValue);
                    }
                    values.clear();
                } catch (InterruptedException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
            }
        }
    }
}


public class Test {
    public static void main(String[] args) {
        Queue<Integer> values = new LinkedList<Integer>();
        ProducerThread producer = new ProducerThread(values);
        ConsumerThread consumer = new ConsumerThread(values);

        consumer.start();
        producer.start();

    }
}

啊哈!您遇到了可怕的竞争条件!

在您的 ProducerThread notify return 秒之后,所述线程仍具有锁。被 notify 唤醒的 ConsumerThread 会发现锁不可用,并会等到它可用。

然后 ProducerThread 放弃锁,然后它将与 ConsumerThread 进行竞争以取回该锁(ProducerThread 通过重新进入 synchronized 块,并且 ConsumerThread 必须从 wait 到 return)。无法保证其中哪一个会获胜。

如果您希望 ProducerThread 等待物品被消耗后再生产更多,您应该考虑另一个 wait/notify 用于该场景。

编辑:这张图片可能有助于更清楚地解释事情。