Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to use ConcurrentLinkedQueue?

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?


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.

One more question: do I need to do this in the remove method:

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

I only have one consumer and one producer.

like image 877
Ricardo Felgueiras Avatar asked Mar 05 '09 20:03

Ricardo Felgueiras


People also ask

How do you iterate ConcurrentLinkedQueue?

ConcurrentLinkedQueue iterator() method in JavaThe iterator() method of ConcurrentLinkedQueue is used to returns an iterator of the same elements as this ConcurrentLinkedQueue in a proper sequence. The elements returned from this method contains elements in order from first(head) to last(tail).

How is ConcurrentLinkedQueue thread-safe?

An unbounded thread-safe queue based on linked nodes. This queue orders elements FIFO (first-in-first-out). The head of the queue is that element that has been on the queue the longest time.

What is a ConcurrentLinkedQueue?

ConcurrentLinkedQueue is an unbounded thread-safe queue which arranges the element in FIFO. New elements are added at the tail of this queue and the elements are added from the head of this queue. ConcurrentLinkedQueue class and its iterator implements all the optional methods of the Queue and Iterator interfaces.


2 Answers

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.

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):

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):

YourObject myObject = queue.poll(); 

For more info see the 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.

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:

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.

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:

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 probably won't block, because you aren't likely to put two billion objects into the queue.

like image 67
Adam Jaskiewicz Avatar answered Oct 08 '22 20:10

Adam Jaskiewicz


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?

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 not guaranteed 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 not automatically 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:

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

Again...atomic calls to the queue are automatically thread-safe. Non-atomic calls are not.

like image 43
Jared Avatar answered Oct 08 '22 20:10

Jared