62

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?

Steve Kuo
  • 61,876
  • 75
  • 195
  • 257
  • 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! – paiego Dec 31 '19 at 06:03

3 Answers3

66

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

Guido
  • 46,642
  • 28
  • 120
  • 174
Matthew Flaschen
  • 278,309
  • 50
  • 514
  • 539
  • 1
    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 May 03 '12 at 13:20
  • @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. – Matthew Flaschen May 04 '12 at 00:24
  • "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 Jun 25 '21 at 11:23
17

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

Ravindra babu
  • 37,698
  • 11
  • 250
  • 211
Amrish Pandey
  • 800
  • 1
  • 7
  • 11
  • 7
    This answer makes a valid observation, but misses that the implementers of LinkedBlockingQueue were aware of this problem and addressed it. Details here: http://stackoverflow.com/questions/26543807/is-blockingqueue-completely-thread-safe-in-java/26543940#26543940 – Chris K Oct 24 '14 at 08:39
  • 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 – Amrish Pandey Oct 24 '14 at 08:43
  • 1
    This answer is incorrect. `add` and `take` are thread-safe and can be used concurrently without extra synchronization. – ens Jan 19 '16 at 17:30
  • Corrected my answer. Simultaneous add and take are not synchronized except during edge condition of queue full / empty. – Amrish Pandey Jan 20 '16 at 03:48
  • 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. – Suma Jun 19 '19 at 15:40
  • yes, no need to synchronise manually since the implementation provides for it. Implementation is smart enough to synchronise add with remove and vice versa only when queue is empty / full. Check implementation of this in the source code. This will be become more clear – Amrish Pandey Jun 21 '19 at 04:28
  • The worrying part of a single lock for `add()` is that many threads could be slowed down when inserting at the same time since add()'s should go through serially. – Basil Musa Nov 01 '22 at 14:35
-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.

Java Guru
  • 466
  • 4
  • 12
  • 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. " – Farid Jun 25 '21 at 11:25