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

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!

Related

Are Synchronized Blocks needed for Blocking Queues

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.

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.

What are the not thread-Safe cases when using HashMap in Java?

In the API documents, we can see:
If multiple threads access a hash map concurrently, and at least one of the threads modifies the map structurally, it must be
synchronized externally. (A structural modification is any operation
that adds or deletes one or more mappings; merely changing the value
associated with a key that an instance already contains is not a
structural modification.)
I'm thinking if the "put" method should be synchronized ? It said only the structural modification. Can you give some unsafe cases for the HashMap. And when I view the source code of "HashTable", the "get" method is also been synchronized, why not only the write operations be synchronized?
There is a general rule of thumb:
If you have more than one thread accessing a collection and at least one thread modifies the collection at some point, you need to synchronize all accesses to the collection.
If you think about it, its very clear: If a collection is modified while another thread reads from it (e.g. iterates), read and write operation can interfere with each other (the read seeing a partial write, e.g. entry created but value not yet set or entry not properly linked yet).
Exempt from this are collections one thread creates and modifies, then hands of to "the world" but never modifies them after publishing their reference.
why not only the write operations be synchronized?
If the reads are not synchronized as well, you might encounter visibility issues. Not only that, but it is also possible to completely thrash the object, if it performs structural changes!
The JVM specification gives a few guarantees regarding when modifications to a memory location made by one thread will be visible to other threads. One such guarantee is that modifications by a thread prior to releasing a lock are visible to threads that subsequently acquire the same lock. That's why you need to synchronized the read operations as well, even in the absence of concurrent structural modifications to the object.
Note that this releasing/acquiring locks is not the only way to guarantee visibility of memory modifications, but it's the easiest. Others include order of starting threads, class initialization, reads/writes to memory locations... more sophisticated stuff (and possibly more scalable on a highly concurrent environment, due to a reduced level of contention).
If you don't use any of those other techniques to ensure visibility, then simply locking only on write operations is wrong code. You might or might not encounter visibility issues though -- there's no guarantee that the JVM will fail, but it's possible, so... wrong code.
I'd suggest you read the book "Java Concurrency in Practice", one of the best texts on the subject I've ever read, after the JVM spec itself. Obviously, the book is way easier (still far from trivial!) and more fun to read than the spec...
One example would be:
Thread 1:
Iterator<YourType> it = yourMapInstance.entrySet().iterator();
while(it.hasNext()) {
it.next().getValue().doSth();
Thread.sleep(1000);
}
}
Thread 2:
for(int i = 0; i < 10; i++) {
if(Math.random() < 0.5) {
yourMapInstance.clear();
Thread.sleep(500);
}
}
Now, if both threads are executed concurrently, at some point there might be a situation, that you have a value in your iterator, while the other thread has already deleted everything from the map. In this case, synchronization is required.

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

Are LinkedBlockingQueue's insert and remove methods thread safe?

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.

Categories

Resources