Java 如何使用 ConcurrentLinkedQueue?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/616484/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How to use ConcurrentLinkedQueue?
提问by Ricardo Felgueiras
How do I use a ConcurrentLinkedQueue
in Java?
Using this LinkedQueue
, do I need to be worried about concurrency in the queue? Or do I just have to define two methods (one to retrive elements from the list and another to add elements to the list)?
Note: obviously these two methods have to be synchronized. Right?
我如何ConcurrentLinkedQueue
在 Java 中使用 a ?
使用这个LinkedQueue
,我需要担心队列中的并发吗?或者我是否只需要定义两种方法(一种从列表中检索元素,另一种将元素添加到列表中)?
注意:显然这两种方法必须同步。对?
EDIT:What I'm trying to do is this: I have a class (in Java) with one method to retrieve items from the queue and another class with one method to add items to the queue. The items added and retrieved from the list are objects of my own class.
编辑:我想要做的是:我有一个类(在 Java 中),它使用一种方法从队列中检索项目,另一个类使用一种方法将项目添加到队列中。从列表中添加和检索的项目是我自己的类的对象。
One more question: do I need to do this in the remove method:
还有一个问题:我是否需要在 remove 方法中执行此操作:
while (queue.size() == 0){
wait();
queue.poll();
}
I only have one consumer and one producer.
我只有一个消费者和一个生产者。
采纳答案by Adam Jaskiewicz
No, the methods don't need to be synchronized, and you don't need to define any methods; they are already in ConcurrentLinkedQueue, just use them. ConcurrentLinkedQueue does all the locking and other operations you need internally; your producer(s) adds data into the queue, and your consumers poll for it.
不,方法不需要同步,也不需要定义任何方法;它们已经在 ConcurrentLinkedQueue 中,只需使用它们。ConcurrentLinkedQueue 在内部完成您需要的所有锁定和其他操作;您的生产者将数据添加到队列中,而您的消费者则对其进行轮询。
First, create your queue:
首先,创建您的队列:
Queue<YourObject> queue = new ConcurrentLinkedQueue<YourObject>();
Now, wherever you are creating your producer/consumer objects, pass in the queue so they have somewhere to put their objects (you could use a setter for this, instead, but I prefer to do this kind of thing in a constructor):
现在,无论您在何处创建生产者/消费者对象,都要传入队列,以便它们有地方放置对象(您可以为此使用 setter,但我更喜欢在构造函数中执行此类操作):
YourProducer producer = new YourProducer(queue);
and:
和:
YourConsumer consumer = new YourConsumer(queue);
and add stuff to it in your producer:
并在您的生产者中添加内容:
queue.offer(myObject);
and take stuff out in your consumer (if the queue is empty, poll() will return null, so check it):
并在您的消费者中取出东西(如果队列为空,poll() 将返回 null,因此请检查它):
YourObject myObject = queue.poll();
For more info see the Javadoc
有关更多信息,请参阅Javadoc
EDIT:
编辑:
If you need to block waiting for the queue to not be empty, you probably want to use a LinkedBlockingQueue, and use the take() method. However, LinkedBlockingQueue has a maximum capacity (defaults to Integer.MAX_VALUE, which is over two billion) and thus may or may not be appropriate depending on your circumstances.
如果您需要阻塞等待队列不为空,您可能需要使用LinkedBlockingQueue,并使用 take() 方法。但是,LinkedBlockingQueue 具有最大容量(默认为 Integer.MAX_VALUE,超过 20 亿),因此可能适合也可能不适合,具体取决于您的情况。
If you only have one thread putting stuff into the queue, and another thread taking stuff out of the queue, ConcurrentLinkedQueue is probably overkill. It's more for when you may have hundreds or even thousands of threads accessing the queue at the same time. Your needs will probably be met by using:
如果您只有一个线程将内容放入队列,而另一个线程将内容从队列中取出,则 ConcurrentLinkedQueue 可能有点矫枉过正。当您可能有数百甚至数千个线程同时访问队列时,更是如此。使用以下方法可能会满足您的需求:
Queue<YourObject> queue = Collections.synchronizedList(new LinkedList<YourObject>());
A plus of this is that it locks on the instance (queue), so you can synchronize on queue to ensure atomicity of composite operations (as explained by Jared). You CANNOT do this with a ConcurrentLinkedQueue, as all operations are done WITHOUT locking on the instance (using java.util.concurrent.atomic variables). You will NOT need to do this if you want to block while the queue is empty, because poll() will simply return null while the queue is empty, and poll() is atomic. Check to see if poll() returns null. If it does, wait(), then try again. No need to lock.
这样做的一个好处是它锁定了实例(队列),因此您可以在队列上进行同步以确保复合操作的原子性(如 Jared 所解释的)。您不能使用 ConcurrentLinkedQueue 执行此操作,因为所有操作都是在不锁定实例的情况下完成的(使用 java.util.concurrent.atomic 变量)。如果您想在队列为空时阻塞,则不需要这样做,因为 poll() 将在队列为空时简单地返回 null,而 poll() 是原子的。检查 poll() 是否返回 null。如果是,请等待(),然后再试一次。无需锁定。
Finally:
最后:
Honestly, I'd just use a LinkedBlockingQueue. It is still overkill for your application, but odds are it will work fine. If it isn't performant enough (PROFILE!), you can always try something else, and it means you don't have to deal with ANY synchronized stuff:
老实说,我只是使用 LinkedBlockingQueue。它对您的应用程序来说仍然是矫枉过正,但很有可能它会正常工作。如果它的性能不够(配置文件!),你总是可以尝试其他的东西,这意味着你不必处理任何同步的东西:
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.
Everything else is the same. Put probablywon't block, because you aren't likely to put two billion objects into the queue.
其他一切都是一样的。Put可能不会阻塞,因为您不太可能将 20 亿个对象放入队列中。
回答by Hank Gay
回答by Ben S
Just use it as you would a non-concurrent collection. The Concurrent[Collection] classes wrap the regular collections so that you don't have to think about synchronizing access.
就像使用非并发集合一样使用它。Concurrent[Collection] 类包装了常规集合,这样您就不必考虑同步访问。
Edit:ConcurrentLinkedList isn't actually just a wrapper, but rather a better concurrent implementation. Either way, you don't have to worry about synchronization.
编辑:ConcurrentLinkedList 实际上不仅仅是一个包装器,而是一个更好的并发实现。无论哪种方式,您都不必担心同步。
回答by Jared
This is largely a duplicate of another question.
Here's the section of that answer that is relevant to this question:
以下是与此问题相关的答案部分:
Do I need to do my own synchronization if I use java.util.ConcurrentLinkedQueue?
如果我使用 java.util.ConcurrentLinkedQueue,是否需要自己进行同步?
Atomic operations on the concurrent collections are synchronized for you. In other words, each individual call to the queue is guaranteed thread-safe without any action on your part. What is notguaranteed thread-safe are any operations you perform on the collection that are non-atomic.
并发集合上的原子操作会为您同步。换句话说,对队列的每个单独调用都保证线程安全,无需您采取任何操作。什么是不保证线程安全的,你在那些非原子集合执行任何操作。
For example, this is threadsafe without any action on your part:
例如,这是线程安全的,您无需执行任何操作:
queue.add(obj);
or
或者
queue.poll(obj);
However; non-atomic calls to the queue are not automatically thread-safe. For example, the following operations are notautomatically threadsafe:
然而; 对队列的非原子调用不是自动线程安全的。例如,以下操作不是自动线程安全的:
if(!queue.isEmpty()) {
queue.poll(obj);
}
That last one is not threadsafe, as it is very possible that between the time isEmpty is called and the time poll is called, other threads will have added or removed items from the queue. The threadsafe way to perform this is like this:
最后一个不是线程安全的,因为很可能在调用 isEmpty 和调用 poll 之间,其他线程会从队列中添加或删除项目。执行此操作的线程安全方式如下所示:
synchronized(queue) {
if(!queue.isEmpty()) {
queue.poll(obj);
}
}
Again...atomic calls to the queue are automatically thread-safe. Non-atomic calls are not.
再次......对队列的原子调用是自动线程安全的。非原子调用不是。
回答by siddhadev
The ConcurentLinkedQueue is a very efficient wait/lock free implementation (see the javadoc for reference), so not only you don't need to synchronize, but the queue will not lock anything, thus being virtually as fast as a non synchronized (not thread safe) one.
ConcurentLinkedQueue 是一个非常有效的无等待/无锁实现(请参阅 javadoc 以供参考),因此不仅您不需要同步,而且队列不会锁定任何东西,因此几乎与非同步(不是线程)一样快安全)一个。
回答by marq
This is probably what you're looking for in terms of thread safety & "prettyness" when trying to consume everything in the queue:
在尝试使用队列中的所有内容时,这可能是您在线程安全性和“美观”方面正在寻找的内容:
for (YourObject obj = queue.poll(); obj != null; obj = queue.poll()) {
}
This will guarantee that you quit when the queue is empty, and that you continue to pop objects off of it as long as it's not empty.
这将保证您在队列为空时退出,并且只要队列不为空,您就可以继续从中弹出对象。