64

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?

1
  • If they weren't thread safe, then you'd need to synchronize it. Then a take() might very well grab the mutex of an empty queue, blocking any other thread from adding to it. Hello deadlock! Commented Dec 31, 2019 at 6:03

3 Answers 3

69

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."

EDIT: The addAll behavior is not a multithreading-specific issue, because a single-threaded scenario can have exactly the same problem.

In a single-threaded app, create an ArrayList list with 9 non-null elements and one null element at the end.

Call queue.addAll(list);

Assuming it adds the elements in sequential order (I don't believe this is guaranteed but it likely will), it will add the first 9, then throw an exception. (BlockingQueue does not allow null elements.) The 9 will still get added to the queue.

  1. Asking for addAll to be atomic is asking a lot, whether the collection is thread-safe or not. It requires snapshoting the whole collection then rolling back. Yes, it could be implemented for many collections (though for some it would be complex), but I wouldn't assume any collection (thread-safe or not) did.

Bottom line: Collections are complex and their guarantees vary. It's important to consult the documentation. Thread-safety is just one concern of many.

Sign up to request clarification or add additional context in comments.

4 Comments

isnt it actually. No, not if you are just using add and take, but if you would use a bulk operation you would have to synchronize it instead of just plain "Yes"? Or am i reading the doc wrong?
@cproinger, no, you never have to synchronize it, as long as you're willing to deal with addAll throwing an exception after adding a subset of the items (or similar). It depends how you define thread-safe. You're right that the bulk methods don't have an atomicity guarantee.
"So it is possible, for example, for addAll(c) to fail (throwing an exception) after adding only some of the elements in c." isn't this a "no"?
@Farid it's a "yes". It's thread-safe. I edited my answer to explain further.
18

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

7 Comments

This answer makes a valid observation, but misses that the implementers of LinkedBlockingQueue were aware of this problem and addressed it. Details here: stackoverflow.com/questions/26543807/…
Yes , i agree. LInkedBlockingQueue offers betters concurrency than ArrayBlockingQueue and maintains thread safety by synchronizing edge condition only. Insert and remove methods have been smartly synchronized for edge cases only
This answer is incorrect. add and take are thread-safe and can be used concurrently without extra synchronization.
Corrected my answer. Simultaneous add and take are not synchronized except during edge condition of queue full / empty.
I think the answer is confusing. I think even when they are not synchronized, they are still safe and there is no need to synchronize manually.
|
-1

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.

1 Comment

It's just advertised as thread-safe, in reality docs read "So it is possible, for example, for addAll(c) to fail (throwing an exception) after adding only some of the elements in c. "

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.