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.
Related
public BlockingQueue<Message> Queue;
Queue = new LinkedBlockingQueue<>();
I know if I use, say a synchronized List, I need to surround it in synchronized blocks to safely use it across threads
Is that the same for Blocking Queues?
No you do not need to surround with synchronized blocks.
From the JDK javadocs...
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.
Just want to point out that from my experience the classes in the java.util.concurrent package of the JDK do not need synchronization blocks. Those classes manage the concurrency for you and are typically thread-safe. Whether intentional or not, seems like the java.util.concurrent has superseded the need to use synchronization blocks in modern Java code.
Depends on use case, will explain 2 scenarios where you may need synchronized blocks or dont need it.
Case 1: Not required while using queuing methods e.g. put, take etc.
Why not required is explained here, important line is below:
BlockingQueue implementations are thread-safe. All queuing methods
achieve their effects atomically using internal locks or other forms
of concurrency control.
Case 2: Required while iterating over blocking queues and most concurrent collections
Since iterator (one example from comments) is weakly consistent, meaning it reflects some but not necessarily all of the changes that have been made to its backing collection since it was created. So if you care about reflecting all changes you need to use synchronized blocks/ Locks while iterating.
You are thinking about synchronization at too low a level. It doesn't have anything to do with what classes you use. It's about protecting data and objects that are shared between threads.
If one thread is able to modify any single data object or group of related data objects while other threads are able to look at or modify the same object(s) at the same time, then you probably need synchronization. The reason is, it often is not possible for one thread to modify data in a meaningful way without temporarily putting the data into an invalid state.
The purpose of synchronization is to prevent other threads from seeing the invalid state and possibly doing bad things to the same data or to other data as a result.
Java's Collections.synchronizedList(...) gives you a way for two or more threads to share a List in such a way that the list itself is safe from being corrupted by the action of the different threads. But, It does not offer any protection for the data objects that are in the List. If your application needs that protection, then it's up to you to supply it.
If you need the equivalent protection for a queue, you can use any of the several classes that implement java.util.concurrent.BlockingQueue. But beware! The same caveat applies. The queue itself will be protected from corruption, but the protection does not automatically extend to the objects that your threads pass through the queue.
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!
I need to have a thread-safe LIFO structure and found that I can use thread-safe implementations of Deque for this. Java 7 has introduced ConcurrentLinkedDeque and Java 6 has LinkedBlockingDeque.
If I were to use only the non-blocking methods in LinkedBlockingDeque such as addFirst() and removeFirst() does it have any difference to ConcurrentLinkedDeque?
i.e. If you disregard the blocking aspect, is there any other difference between ConcurrentLinkedDeque and LinkedBlockingDeque, apart from LinkedBlockingDeque being bounded?
To quote the great Doug Lea (my emphasis)
LinkedBlockingDeque vs ConcurrentLinkedDeque
The LinkedBlockingDeque class is intended to be the "standard" blocking deque class. The current implementation has relatively low overhead but relatively poor scalability. ...
... ConcurrentLinkedDeque has almost the opposite performance profile as LinkedBlockingDeque: relatively high overhead, but very good scalability. ... in concurrent applications, it is not all that common to want a Deque that is thread safe yet does not support blocking. And most of those that do are probably better off with special-case solutions.
He seems to be suggesting that you should use LinkedBlockingDeque unless you specifically need the features of ConcurrentLinkedDeque.
ConcurentLinkedDequeue is lock-free (see comments in source code) while LinkedBlockingQueue uses locking. That is the former is supposed to be more efficient
Two things:
1: If I were to use only the non-blocking methods in LinkedBlockingDeque such as addFirst() and removeFirst() does it have any difference to ConcurrentLinkedDeque?
These methods do have difference in terms of concurrent locking behavior, in LinkedBlockingDeque:
public E removeFirst() {
E x = pollFirst();
..
}
public E pollFirst() {
lock.lock(); //Common lock for while list
try {
return unlinkFirst();
} finally {
lock.unlock();
}
}
Similarly for addFirst method. In ConcurrentLinkedDeque this locking behavior for both the method is different and is more efficient as it doesn't lock the whole list but a subset of it, checking source for ConcurrentLinkedDeque will give you more clarity on this.
2: From javadoc of ConcurrentLinkedDeque:
Beware that, unlike in most collections, the size method is NOT a
constant-time operation.
..
Additionally, the bulk operations addAll, removeAll, retainAll,
containsAll, equals, and toArray are not guaranteed to be performed
atomically.
Above is not true for LinkedBlockingDeque
First thing both LinkedBlockingDeque and ConcurrentLinkedDeque both are thread safe but which one to use depends on your application requirement.
For example,
LinkedBlockingDequeue : Use this collection if you want that at a time only single thread can operate on your data and when you need blocking for your application.
ConcurrentLinkedDeque: This is also thread safe collection deque, If you application is multi threaded and you want that each one of your thread can access the data then ConcurrentLinkedDequeue is the best choise for it.
As in your question,
1. I need to have a thread-safe LIFO structure,
Use LinkedBlockingDeque if at a time you want only single thread can operate your data.
Use ConcurrentLinkedDeque if you want that each thread can access the shared data
2. If you disregard the blocking aspect, is there any other difference between ConcurrentLinkedDeque and LinkedBlockingDeque,
Yes, there is a difference as LinkedBlockingDeque is using locking mechanism and ConcurrentLinkedDeque is not this may affect the performance when you want to operate your data.
I would like multiple threads to iterate through the elements in a LinkedList. I do not need to write into the LinkedList. Is it safe to do so? Or do I need a synchronized list to make it work?
Thank you!
They can do this safely, PROVIDED THAT:
they synchronize with (all of) the threads that have written the list BEFORE they start the iterations, and
no threads modify the list during the iterations.
The first point is necessary, because unless there is proper synchronization before you start, there is a possibility that one of the "writing" threads has unflushed changes for the list data structures in local cache memory or registers, or one of the reading threads has stale list state in its cache or registers.
(This is one of those cases where a solid understanding of the Java memory model is needed to know whether the scenario is truly thread-safe.)
Or do I need a synchronized list to make it work
You don't necessarily need to go that far. All you need to do is to ensure that there is a "happens-before" relationship at the appropriate point, and there are a variety of ways to achieve that. For instance, if the list is created and written by the writer thread, and the writer then passes the list to the reader thread objects before calling start() on them.
From the Java documentation:
Note that this implementation is not synchronized. If multiple threads access a linked list concurrently, and at least one of the threads modifies the list structurally, it must be synchronized externally. (A structural modification is any operation that adds or deletes one or more elements; merely setting the value of an element is not a structural modification.) This is typically accomplished by synchronizing on some object that naturally encapsulates the list. If no such object exists, the list should be "wrapped" using the Collections.
In other words, if you are truly just iterating through then you're alright, just be careful.
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.