不,方法不需要同步,也不需要定义任何方法;它们已经在 ConcurrentLinkedQueue 中,只需使用它们。 ConcurrentLinkedQueue 在内部完成您需要的所有锁定和其他操作;您的生产者将数据添加到队列中,然后您的消费者轮询它。
首先,创建您的队列:
Queue<YourObject> queue = new ConcurrentLinkedQueue<YourObject>();
现在,无论您在哪里创建生产者/消费者对象,都可以传入队列,以便他们有地方放置对象(您可以为此使用 setter,但我更喜欢在构造函数中执行此类操作):
YourProducer producer = new YourProducer(queue);
和:
YourConsumer consumer = new YourConsumer(queue);
并在您的生产者中添加内容:
queue.offer(myObject);
然后从你的消费者中取出东西(如果队列是空的,poll() 将返回 null,所以检查一下):
YourObject myObject = queue.poll();
更多信息见the Javadoc
编辑:
如果您需要阻止等待队列不为空,您可能需要使用LinkedBlockingQueue,并使用 take() 方法。但是,LinkedBlockingQueue 具有最大容量(默认为 Integer.MAX_VALUE,超过 20 亿),因此根据您的情况可能合适也可能不合适。
如果您只有一个线程将内容放入队列,而另一个线程将内容从队列中取出,则 ConcurrentLinkedQueue 可能是矫枉过正。当您可能有数百甚至数千个线程同时访问队列时,它更有用。您的需求可能会通过以下方式得到满足:
Queue<YourObject> queue = Collections.synchronizedList(new LinkedList<YourObject>());
这样做的一个优点是它锁定实例(队列),因此您可以在队列上同步以确保复合操作的原子性(正如 Jared 所解释的)。您不能使用 ConcurrentLinkedQueue 执行此操作,因为所有操作都是在没有锁定实例的情况下完成的(使用 java.util.concurrent.atomic 变量)。如果您想在队列为空时阻塞,则不需要这样做,因为 poll() 将在队列为空时简单地返回 null,而 poll() 是原子的。检查 poll() 是否返回 null。如果是,wait(),然后再试一次。无需锁定。
最后:
老实说,我只是使用 LinkedBlockingQueue。对于您的应用程序来说,它仍然是矫枉过正,但它很可能会正常工作。如果性能不够(PROFILE!),您可以随时尝试其他方法,这意味着您不必处理任何同步的东西:
BlockingQueue<YourObject> queue = new LinkedBlockingQueue<YourObject>();
queue.put(myObject); // Blocks until queue isn't full.
YourObject myObject = queue.take(); // Blocks until queue isn't empty.
其他一切都是一样的。 Put 可能不会阻塞,因为您不太可能将 20 亿个对象放入队列中。