不,方法不需要同步,也不需要定义任何方法;它们已经在 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();
有关更多信息,请参阅 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。如果是这样,请等待(),然后重试。无需锁定。
最后:
老实说,我只使用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 亿个对象放入队列中。