【问题标题】:Why ArrayBlockingQueue hasn't been blocked when the queue is full为什么队列满时ArrayBlockingQueue没有被阻塞
【发布时间】:2018-08-12 09:52:02
【问题描述】:

我有一个简单的 ArrayBlockingQueue 测试如下:

public class TestQueue {

    static class Producer implements Runnable {
        private ArrayBlockingQueue<Integer> queue;
        private int index;

        public Producer(ArrayBlockingQueue<Integer> queue, int index) {
            this.queue = queue;
            this.index = index;
        }

        @Override
        public void run() {
            try {
                queue.put(index);

                System.out.println("producer: " + index);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }

    static class Consumer implements Runnable {
        private ArrayBlockingQueue<Integer> queue;

        public Consumer(ArrayBlockingQueue<Integer> queue) {
            this.queue = queue;
        }

        @Override
        public void run() {
            try {
                while(true) {
                    System.out.println("consumer: " + queue.take());
                }
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }

    public static void main(String[] args) {
        ArrayBlockingQueue<Integer> queue = new ArrayBlockingQueue<>(3);

        for (int i = 0; i < 10; i++) {
            Producer producer = new Producer(queue, i);

            new Thread(producer).start();
        }

        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        Consumer consumer = new Consumer(queue);

        new Thread(consumer).start();
    }
}

结果是:

producer: 2
producer: 0
producer: 1
consumer: 0
producer: 4
producer: 6
consumer: 2
etc...

我的问题是,我已经定义了ArrayBlockingQueue的大小为3,而生产者已经将2、0和1,总共3个项目放入队列中,现在队列已经满了,那么消费者已经消费了0,现在队列的大小应该是2,然后生产者将4放入队列,现在队列应该已满,为什么生产者仍然可以将6放入队列,应该是阻塞了

【问题讨论】:

  • 问题出在打印中,System.out.println is not thread safe 所以看起来该值已插入到一个完整的队列中。
  • @Guy 为什么要责备System.out.println?它是线程安全的。

标签: java multithreading queue producer-consumer blockingqueue


【解决方案1】:

take/put 动作和打印不是原子的。

producer: 6在consumer: 2之前打印,并不意味着生产者将6放在消费者消费2之前。

例如:

  1. 消费者执行queue.take(),取2
  2. 生产者执行 queue.put(6)
  3. 生产者打印 生产者:6
  4. 消费者品脱消费者:2

【讨论】:

    【解决方案2】:

    producer: 6 在consumer: 2 之前打印到您的控制台这一事实并不意味着在删除2 之前添加了6。

    如果您在添加和删除项目之前和之后打印队列的大小,您会看到它永远不会超过 3。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2011-03-27
      • 2014-08-11
      • 1970-01-01
      • 2014-03-12
      • 2014-10-16
      • 2019-10-16
      • 2020-05-02
      • 2011-04-10
      相关资源
      最近更新 更多