ArrayBlockingQueue+同步 java

ArrayBlockingQueue+synchronized in java

我在我的代码中使用 ArrayBlockingQueue,它有任何元素。但是线程调用了 take 方法。为什么? 我认为应该调用 take 方法之前的 put 方法。文笔不好请见谅。

你怎么知道在项目可用之前它不会阻塞?

您还应该记录从队列中删除的项目。理想情况下,包括一些有助于识别唯一值的 Id,例如放置时的线程名称。

请记住,队列中的方法是原子的,您的日志记录不是,因此与您尝试调试的事件相比,它可能会乱序发生。

为了使这一点更明显,我会在显示哪些线程正在等待的阻塞方法之前添加日志记录。

我还保存了一些东西,以便很容易看出所截取的消息来自何处。这样您就可以看到这些方法正在阻塞并按预期工作。

import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.BlockingQueue;

public class ArrayBlockingQueueExample {
    public static void main(String[] args) {
        ArrayBlockingQueue<String> blockingQueue = new ArrayBlockingQueue<>(3);
        Thread[] threads = {
            new Producer(blockingQueue),
            new Producer(blockingQueue),
            new Producer(blockingQueue),
            new Producer(blockingQueue),
            new Producer(blockingQueue),
            new Consumer(blockingQueue),
            new Consumer(blockingQueue),
            new Consumer(blockingQueue),
            new Consumer(blockingQueue),
            new Consumer(blockingQueue),
        };

        for(Thread t: threads) {
            t.start();
        }
    }

    static class Consumer extends Thread {
        private final BlockingQueue<String> queue;

        Consumer(BlockingQueue<String> queue) {
            this.queue = queue;
        }

        @Override
        public void run() {
            try {
                System.out.println("Consumer:" + this.getName() + " waiting... ");
                String takenValue = queue.take();
                // Logging here may occur out of order in comparison with the producer thread logging.
                System.out.println("Consumer:" + this.getName() + " received: " + takenValue);
            } catch (InterruptedException e) {
                // Reset the interrupted flag on the thread.
                Thread.currentThread().interrupt();
                e.printStackTrace();
            }
        }
    }

    static class Producer extends Thread {
        private final BlockingQueue<String> queue;

        Producer(BlockingQueue<String> queue) {
            this.queue = queue;
        }

        @Override
        public void run() {
            try {
                String putValue = "Producer:" + this.getName() + " says hello!";
                System.out.println("Producer:" + this.getName() + " waiting... ");
                queue.put(putValue);
                // Logging here may occur out of order in comparison with the consumer thread logging.
                System.out.println("Producer:" + this.getName() + " sent: " + putValue);
            } catch (InterruptedException e) {
                // Reset the interrupted flag on the thread.
                Thread.currentThread().interrupt();
                e.printStackTrace();
            }
        }
    }
}

使用此代码,您将看到类似于以下输出的内容:

Consumer:Thread-5 waiting... 
Consumer:Thread-7 waiting... 
Producer:Thread-1 waiting... 
Producer:Thread-0 waiting... 
Producer:Thread-4 waiting... 
Consumer:Thread-9 waiting... 
Consumer:Thread-8 waiting... 
Consumer:Thread-6 waiting... 
Producer:Thread-2 waiting... 
Producer:Thread-3 waiting... 
Consumer:Thread-6 received: Producer:Thread-0 says hello!
Producer:Thread-2 sent: Producer:Thread-2 says hello!
Consumer:Thread-5 received: Producer:Thread-3 says hello!
Producer:Thread-1 sent: Producer:Thread-1 says hello!
Consumer:Thread-7 received: Producer:Thread-4 says hello!
Consumer:Thread-8 received: Producer:Thread-1 says hello!
Producer:Thread-3 sent: Producer:Thread-3 says hello!
Producer:Thread-4 sent: Producer:Thread-4 says hello!
Consumer:Thread-9 received: Producer:Thread-2 says hello!
Producer:Thread-0 sent: Producer:Thread-0 says hello!

请注意,消费者 (Thread-6) 在第一行记录中收到了来自 Thread-0 生产者的 hello,但是来自 Thread-0 的 sent 记录是记录的最后一行?此顺序与阻塞队列上的放置事件顺序无关。

put()take()的执行顺序无关紧要-效果是一样的,因为它们是阻塞调用。

take() 接受并 returns 下一项,如果 none 可用,请等待。

put() 添加一个项目,如果没有 space 可用,等待被拿走。