Course contents

Blocking and concurrent queues at a glance

BlockingQueue, concurrent queues and queue-selection trade-offs: bounded buffers, hand-offs, priority and delay queues, transfer queues, poison pills and back-pressure.

PremiumOften askedLesson14 min readCoreReviewed Oct 2026 · Java 21
On this page
  1. Picture it first: pick the queue by the kind of waiting
  2. BlockingQueue under the hood: four ways to ask
  3. The BlockingQueue family at a glance
  4. Concurrent non-blocking queues
  5. Producer-consumer with poison pill shutdown
  6. Which one should you choose?
  7. How to say it in the interview

🚦 What are blocking and concurrent queues?

Blocking and concurrent queues are queue implementations designed for threads sharing work safely. A BlockingQueue can make a producer wait when the buffer is full and make a consumer wait when the buffer is empty. A ConcurrentLinkedQueue is different: it is thread-safe and non-blocking, so a failed poll() returns null instead of waiting.

Think of them as different loading docks. Some docks have a bounded waiting area and make trucks wait outside when it fills. Some docks are pure hand-offs with no storage at all. Some docks never block, they just let workers check whether a package is available and move on.

What you’ll learn

  • Choose between blocking, non-blocking, bounded, priority, delay and hand-off queues
  • Explain the four BlockingQueue method families: throwing, special value, blocking and timed
  • Use a bounded ArrayBlockingQueue for producer-consumer back-pressure
  • Avoid the **unbounded LinkedBlockingQueue trap** in fixed thread pools
  • Know what SynchronousQueue, DelayQueue, PriorityBlockingQueue and TransferQueue are for
  • Recognize ConcurrentLinkedQueue and ConcurrentLinkedDeque as lock-free non-blocking queues where size() is O(n)

For this lesson, we'll map the queue family, not rebuild the concurrency machinery underneath it. We'll focus on BlockingQueue method families, ArrayBlockingQueue, LinkedBlockingQueue, PriorityBlockingQueue, DelayQueue, SynchronousQueue, TransferQueue, ConcurrentLinkedQueue, ConcurrentLinkedDeque, LinkedBlockingDeque, back-pressure and the producer-consumer poison-pill pattern. Deeper lock, condition, CAS and memory-model internals are covered in the Concurrency module.

Below the line (out of scope)

The 30-second answer

Use a BlockingQueue when producers and consumers should coordinate through waiting. Its four method families are: throw (add, remove, element), special value (offer, poll, peek), block forever (put, take) and timed wait (offer(e, timeout, unit), poll(timeout, unit)). Start with a bounded ArrayBlockingQueue for a normal producer-consumer buffer because it gives clear back-pressure. Use LinkedBlockingQueue only with an explicit capacity unless you really mean Integer.MAX_VALUE, which is the trap behind many fixed-thread-pool memory incidents. Use SynchronousQueue for direct hand-off, PriorityBlockingQueue for concurrent priority work, DelayQueue for delayed tasks, LinkedTransferQueue when producers may wait for consumers, and ConcurrentLinkedQueue or ConcurrentLinkedDeque when you want lock-free non-blocking access and can handle null on empty.

Interview radar

Asked often: Which collection should I use when producers must wait if the queue is full? Senior rounds probe: LinkedBlockingQueue default capacity, newFixedThreadPool's unbounded queue, SynchronousQueue in cached pools, and why ConcurrentLinkedQueue.size() is O(n). Production angle: Back-pressure is a safety mechanism. An unbounded queue turns latency into memory growth until the JVM falls over.

01Picture it first: pick the queue by the kind of waiting

Start with the question, not the class name: should a thread wait, return immediately, or hand work directly to another thread? Once you answer that, the family becomes much less memorisation-heavy.

The decision tree below is the map I use in code reviews.

Fig. 1

A decision tree starts with whether threads need to wait, then branches to BlockingQueue choices such as bounded FIFO, linked FIFO, priority, delay and hand-off queues, or to non-blocking lock-free FIFO queues

A decision tree starts with whether threads need to wait, then branches to BlockingQueue choices such as bounded FIFO, linked FIFO, priority, delay and hand-off queues, or to non-blocking lock-free FIFO queues

Notice the first fork. BlockingQueue is about coordination through waiting. ConcurrentLinkedQueue is about safe concurrent access without waiting. Both are thread-safe, but they solve different problems.

02BlockingQueue under the hood: four ways to ask

BlockingQueue is the interface behind the classic producer-consumer pattern. It extends Queue, but adds methods that know how to wait for capacity or wait for data.

Try it yourself first

Before reading the table, decide which method you would call if a producer should wait up to 200 milliseconds for space and then give up.

Family Insert Remove Examine What happens on full or empty
Throws exception add(e) remove() element() throws IllegalStateException or NoSuchElementException
Special value offer(e) poll() peek() returns false or null
Blocks put(e) take() not available waits until possible
Times out offer(e, time, unit) poll(time, unit) not available waits up to the timeout

The answer to the prompt is offer(item, 200, TimeUnit.MILLISECONDS). That method is useful when you want back-pressure, but you also want a request thread to fail or shed load instead of waiting forever.

Here is the minimum producer-consumer shape:

import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.TimeUnit;

record OrderJob(String id, int amountCents) {}

BlockingQueue<OrderJob> queue = new ArrayBlockingQueue<>(100);

boolean accepted = queue.offer(new OrderJob("o-42", 49900), 200, TimeUnit.MILLISECONDS);
if (!accepted) {
    throw new IllegalStateException("too many orders queued");
}

OrderJob next = queue.take(); // waits while the queue is empty

Notice three things:

  • put and take are coordination points. They block the calling thread.
  • offer with a timeout is often better at service boundaries because it gives you a limit.
  • BlockingQueue rejects null, so null can safely mean "nothing available" for poll.
Fig. 2

Two producers put jobs into a bounded blocking queue while two consumers take jobs out; when the buffer is full producers wait, creating back-pressure

Two producers put jobs into a bounded blocking queue while two consumers take jobs out; when the buffer is full producers wait, creating back-pressure

Back-pressure is the important production word here. If consumers can process 200 jobs per second and producers send 1,000 jobs per second, a queue does not create capacity. A bounded queue makes the overload visible by slowing or rejecting producers. An unbounded queue hides the overload as growing memory and longer latency.

In the real world

The most common queue incident I've seen is not a race condition. It is a fixed worker pool with an unbounded queue. Traffic spikes, workers keep processing at the same rate, the queue grows for 20 minutes, and then the service dies with OutOfMemoryError. A capacity limit would have forced the caller to slow down or fail earlier, when the system was still healthy enough to explain itself.

03The BlockingQueue family at a glance

Let's name the pieces first, then compare them. You do not need every internal lock path for a Collections interview, but you should know what each queue is for.

ArrayBlockingQueue: bounded array, one lock

ArrayBlockingQueue is a fixed-size circular array. You choose the capacity in the constructor, and it never grows. Internally it uses one lock with two conditions: one for "not empty" and one for "not full".

Premium lesson

Keep reading with the Java Pass

The rest of this lesson is part of Java One-Stop Interview Prep: in-depth explanations, diagrams, model answers and how to say them in the interview.

  • Concurrent non-blocking queues
  • Producer-consumer with poison pill shutdown
  • Which one should you choose?
  • How to say it in the interview

From ₹199 · one-time payment · No auto-renewal

Practise this topicQueues & deques: interview questions & scenarios
Further reading (11)