如何使用ConcurrentLinkedQueue?

如何在Java中使用ConcurrentLinkedQueue
使用这个LinkedQueue ,我需要担心队列中的并发吗? 或者我只需要定义两个方法(一个从列表中检索元素,另一个向列表中添加元素)?
注意:显然这两个方法必须同步。 对?


编辑:我想要做的是这样的:我有一个类(在Java中)与一种方法来检索项目从队列和另一个类用一种方法添加项目到队列。 从列表中添加和检索的项目是我自己class级的对象。

还有一个问题:我需要在删除方法中执行此操作:

 while (queue.size() == 0){ wait(); queue.poll(); } 

我只有一个消费者和一个生产者。

不,这些方法不需要同步,也不需要定义任何方法。 他们已经在ConcurrentLinkedQueue中,只是使用它们。 ConcurrentLinkedQueue在内部完成所有的locking和内容; 你的制作人只是提供一些东西进入队列,而你的消费者则会进行调查。

首先,创build你的队列:

 Queue<YourObject> queue = new ConcurrentLinkedQueue<YourObject>(); 

现在,无论你在哪里创build生产者/消费者对象,都要传入队列,以便他们有地方放置它们的对象(你可以使用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>()); 

另外一个好处就是它locking实例(队列),所以你可以在队列上进行同步以确保组合操作的primefaces性(如Jared所解释的)。 你不能用ConcurrentLinkedQueue来完成,因为所有的操作都是在不locking实例的情况下完成的(使用java.util.concurrent.atomicvariables)。 如果要在队列为空时阻塞,则不需要执行此操作,因为poll()将仅在队列为空时返回null,而poll()是primefaces操作。 检查poll()是否返回null。 如果是,等待(),然后再试一次。 不需要locking。

最后:

老实说,我只是使用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. 

其他一切都是一样的。 看起来可能不会阻塞,因为你不可能把20亿个对象放入队列。

这在很大程度上是另一个问题的重复 。

以下是与该问题相关的答案部分:

如果我使用java.util.ConcurrentLinkedQueue,是否需要执行自己的同步?

并发集合上的primefaces操作是同步的。 换句话说,每个单独的队列调用都是保证线程安全的,而不需要任何操作。 保证线程安全的是你在集合上执行的任何非primefaces操作。

例如,这是线程安全的,没有您的任何操作:

 queue.add(obj); 

要么

 queue.poll(obj); 

然而; 对队列的非primefaces调用不是自动线程安全的。 例如,以下操作不会自动进行线程安全:

 if(!queue.isEmpty()) { queue.poll(obj); } 

最后一个不是线程安全的,因为在调用isEmpty和调用时间轮询之间很可能会有其他线程添加或删除队列中的项目。 线程安全的方式是这样的:

 synchronized(queue) { if(!queue.isEmpty()) { queue.poll(obj); } } 

再一次…对队列的primefaces调用是自动线程安全的。 非primefaces调用不是。

使用poll来获取第一个元素,并添加一个新的最后一个元素。 就是这样,没有同步或其他任何东西。

在尝试占用队列中的所有内容时,这可能就是线程安全和“漂亮”

 for (YourObject obj = queue.poll(); obj != null; obj = queue.poll()) { } 

这将保证您在队列为空时退出,并且只要不是空的,就继续popup对象。

只要像使用非并发集合一样使用它即可。 Concurrent [Collection]类封装了常规集合,因此您不必考虑同步访问。

编辑: ConcurrentLinkedList实际上不是一个包装,而是一个更好的并发实现。 无论哪种方式,你不必担心同步。

ConcurentLinkedQueue是一个非常有效的等待/locking实现(请参阅javadoc以供参考),所以不仅不需要同步,而且队列也不会locking任何东西,因此几乎与非同步一样快(不是线程安全)一个。