Are LinkedBlockingQueue's insert and remove methods thread safe? - java

I'm using LinkedBlockingQueue between two different threads. One thread adds data via add, while the other thread receives data via take.
My question is, do I need to synchronize access to add and take. Is LinkedBlockingQueue's insert and remove methods thread safe?

Yes. From the docs:
"BlockingQueue implementations are
thread-safe. All queuing methods
achieve their effects atomically using
internal locks or other forms of
concurrency control. However, the bulk
Collection operations addAll,
containsAll, retainAll and removeAll
are not necessarily performed
atomically unless specified otherwise
in an implementation. So it is
possible, for example, for addAll(c)
to fail (throwing an exception) after
adding only some of the elements in
c."

Yes, BlockingQueue methods add() and take() are thread safe but with a difference.
add () and take() method uses 2 different ReentrantLock objects.
add() method uses
private final ReentrantLock putLock = new ReentrantLock();
take() method uses
private final ReentrantLock takeLock = new ReentrantLock();
Hence, simultaneous access to add() method is synchronized. Similarly, simultaneous access to take() method is synchronized.
But, simultaneous access to add() and take() method is not synchronized since they are using 2 different lock objects (except during edge condition of queue full / empty).

Simply Yes, its definitely thread safe otherwise it wouldn't have qualified as a candidate for storing element for ThreadPoolExecutor.
Simply add and retrieve element without worrying about concurrency for BlockingQueue.

Related

Is synchronized enough to make the drainTo() method of a BlockingQueue atomic?

If I simply do something like this:
synchronized(taskQueue) { //taskQueue is a BlockingQueue
taskQueue.drainTo(tasks); //tasks is a list
}
Am I assured that concurrent calls to taskQueue.put() and taskQueue.take() can not be executed inside the synchronized block?
In other words, am I making the drainTo() method atomic?
Or more generally, how do I make a composition of thread safe operations atomic?
Example:
if(taskQueue.size() == 1) {
/*Do a lot of things here, but I do not want other threads
to change the size of the queue here with take or put*/
}
//taskQueue.size() must still be equal to 1
See below excerpt from Java docs of BlockingQueue
BlockingQueue implementations are thread-safe. All queuing methods achieve their effects atomically using internal locks or other forms
of concurrency control. However, the bulk Collection operations
addAll, containsAll, retainAll and removeAll are not necessarily
performed atomically unless specified otherwise in an implementation.
So it is possible, for example, for addAll(c) to fail (throwing an
exception) after adding only some of the elements in c.
Also, check the example which shows that a BlockingQueue implementation can safely be used with multiple producers and multiple consumers.
So, if you are not using bulk Collection operations like addAll, containsAll, retainAll and removeAll then you are thread safe.
You even don't need synchronized(taskQueue) { and can directly use taskQueue.drainTo(tasks); because BlockingQueue implementations are thread-safe for non-bulk-collection operations like put, take, drainTo etc.
Hope this helps!
Take a LinkedBlockingQueue as an example, it has a 'takeLock' and 'putLock' which are its member variables.
So client side synchronization dose not help here, since other 'take' actions are not guarded by this lock, even if this lock comes from the queue itself.
The drainTo() method is guarded by 'takeLock', for any other 'take' operation it's thread safe. But for the 'put' operations, they are guarded by 'putLock', so will not be affected.
So I think nothing is needed here!

Java (Android), thread safe FIFO without locking?

I have a producer-consumer situation with exactly two threads. One takes objects from a pool and puts them in a fifo, the other one reads the objects (multiples at a time), does calculations, removes them from the list and puts them back in the pool.
With ConcurrentLinkedQueue that pattern should be thread safe without additional locks. Each object is only written once, read once and removed once. Add() and Poll() are safe in CLQ.
a) Is this correct?
b) Which other Containers support this specific pattern? I remember things about LinkedList or even ArrayList being safe because of some atomic effects with "getSize()" or "head=..." but i am not sure and could not find it.
Yes, the methods add and poll of ConcurrentLinkedQueue are thread-safe (as all other methods).
No, do not use ArrayList or LinkedList directly in a concurrent environment. These classes are not thread-safe by definition:
Note that this implementation is not synchronized. If multiple threads access an ArrayList instance concurrently, and at least one of the threads modifies the list structurally, it must be synchronized externally.
If you are not satisfied with ConcurrentLinkedQueue, have a look at all those container implementations in package java.util.concurrent:
ConcurrentLinkedDeque (is a Queue)
LinkedBlockingQueue (is a BlockingQueue)
LinkedBlockingDeque (is a BlockingDeque)
ArrayBlockingQueue (is a BlockingQueue)
I assume, either Queue or BlockingQueue is the interface of your choice.

Sync block required for Collections.synchronizedList.add()?

My understanding of this is that a synchronized block keeps other threads from accessing until such time as that block terminates; that is, they are put on hold till then via a lock held by the currently executing class (?).
So I wrap a for block which iterates over a list and then calls clear() on that list directly thereafter, in a synchronized block. as I can't afford to have other threads adding to the list between those two sets of operations. This is in accordance with the docs, which say,
It is imperative that the user manually synchronize on the returned
collection when iterating over it...
However I can't figure for sure whether I need to do the same when I am adding to the list. I am guessing not, since in my case the order of add operations from different threads is not important. I guess that what I'm unsure of is whether unsynchronized modify operations might have any negative impacts?
You only need locking when you have multiple operations which must work together. In the case of an Iterator, you will perform any operations over the life of the loop.
If adds can occur in any order, no additional locking is required.
I wrap a for block which iterates over a list and then calls clear()
From your use case, it sounds like a BlockingQueue (is thread safe without synchronized) or even an ExecutorService (which combines a thread pool with a queue) would be a better choice.
It is important that you synchronize on Collection itself
Collection c = Collections.synchronizedCollection(myCollection);
...
synchronized (c) {
for(Object o : c) {
....
}
other threads calling any methods of c will be blocked until you leave the block. No other synchronization is necessary

Do I need extra synchronization when using a BlockingQueue?

I have a simple bean #Entity Message.java that has some normal properties. The life-cycle of that object is as follows
Instantiation of Message happens on Thread A, which is then enqueued into a blockingQueue
Another thread from a pool obtains that object and do some stuff with it and changes the state of Message, after that, the object enters again into the blockingQueue. This step is repeated until a condition makes it stop. Each time the object gets read/write is potentially from a different thread, but with the guarantee that only one thread at a time will be reading/writing to it.
Given that circumstances, do I need to synchronize the getters/setters ? Perhaps make the properties volatile ? or can I just leave without synchronization ?
Thanks and hope I could clarify what I am having here.
No, you do not need to synchronize access to the object properties, or even use volatile on the member variables.
All actions performed by a thread before it queues an object on a BlockingQueue "happen-before" the object is dequeued. That means that any changes made by the first thread are visible to the second. This is common behavior for concurrent collections. See the last paragraph of the BlockingQueue class documentation:
Memory consistency effects: As with other concurrent collections, actions in a thread prior to placing an object into a BlockingQueue happen-before actions subsequent to the access or removal of that element from the BlockingQueue in another thread.
As long as the first thread doesn't make any modifications after queueing the object, it will be safe.
You don't need to do synchronization yourself, because the queue does it for you already.
Visibility is also guaranteed.
If you're sure that only one thread at a time will access your object, then you don't need synchronisation.
However, you can ensure that by using the synchronized keyword: each time you want to access this object and be sure that no other thread is using the same instance, wrap you code in a synchronized block:
Message myMessage = // ...
synchronized (myMessage) {
// You're the only one to have access to this instance, do what you want
}
The synchronized block will acquire an implicit lock on the myMessage object. So, no other synchronized block will have access to the same instance until you leave this block.
It would sound like you could leave of the synchronized off the methods. The synchronized simply locks the object to allow only a single thread to access it. You've already handled that with the blocking queue.
Volatile would be good to use, as that would ensure that each thread has the latest version, instead of a thread local cache value.

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.
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.
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.
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.
Use poll to get the first element, and add to add a new last element. That's it, no synchronization or anything else.
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.
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.
Edit: ConcurrentLinkedList isn't actually just a wrapper, but rather a better concurrent implementation. Either way, you don't have to worry about synchronization.

Categories

Resources