← Home
🏗Crack System Design with DSA AnimatorSystem DesignNEW
🏗 System Design›Concurrency & Threading

📦BlockingQueue (Java Concurrency)

Thread-safe queue with blocking operations for producer-consumer coordination.

📌 Key IdeaBlockingQueue is a java.util.concurrent interface for safe handoff between producer and consumer threads. put() blocks when full; take() blocks when empty — giving natural backpressure inside one JVM.
🧩

Problem it solves

  • Manual producer-consumer code with wait()/notify() is error-prone and hard to maintain.
  • Without bounded handoff, fast producers can overwhelm consumers and cause memory pressure.
  • BlockingQueue provides safe coordination and natural in-process backpressure.
🖼

Visual

📦 Producer-Consumer with built-in backpressure
Producer threads --put()--> [ BlockingQueue ] --take()--> Consumer threads

Queue full  -> put() blocks producer
Queue empty -> take() blocks consumer

No manual wait()/notify() needed.
✅

When to Use

  • Producer-consumer pipelines where multiple threads exchange tasks/data.
  • You need in-memory backpressure instead of unbounded memory growth.
  • You want thread-safe coordination without writing lock/wait-notify code.
🚫

When NOT to Use

  • You need durable messaging across process restarts (use Kafka/RabbitMQ, etc.).
  • Cross-service communication (BlockingQueue is in-process only).
  • No clear capacity planning for bounded queues under peak load.
💻

Code Variations

1️⃣ Simple producer-consumerjava
BlockingQueue<String> queue = new ArrayBlockingQueue<>(10);

new Thread(() -> {
    while (!Thread.currentThread().isInterrupted()) {
        try { queue.put("Message"); } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
        }
    }
}).start();

new Thread(() -> {
    while (!Thread.currentThread().isInterrupted()) {
        try {
            String msg = queue.take();
            System.out.println("Consumed: " + msg);
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
        }
    }
}).start();
Use interrupt handling instead of swallowing exceptions; this avoids stuck shutdowns.
2️⃣ ThreadPoolExecutor + BlockingQueue (production pattern)java
ThreadPoolExecutor exec = new ThreadPoolExecutor(
    8, 16, 60, TimeUnit.SECONDS,
    new ArrayBlockingQueue<>(500),
    new ThreadPoolExecutor.CallerRunsPolicy()
);
Queue + rejection policy controls overload behavior explicitly.
3️⃣ PriorityBlockingQueue for priority jobsjava
record Job(int priority, long seq, Runnable task)
        implements Comparable<Job> {
    public int compareTo(Job o) {
        int p = Integer.compare(o.priority, this.priority); // high first
        return p != 0 ? p : Long.compare(this.seq, o.seq);  // tie-breaker
    }
}
BlockingQueue<Job> q = new PriorityBlockingQueue<>();
PriorityBlockingQueue is unbounded by default — add producer throttling or external limits.
⚖️

Pros & Cons

👍 Pros
  • Thread-safe out of the box.
  • Natural backpressure via blocking semantics.
  • Simplifies concurrency by avoiding manual wait() / notify().
  • Works seamlessly with executor-based architectures.
👎 Cons
  • Blocking can reduce throughput if capacity and consumer count are poorly tuned.
  • In-memory only — no durability on process crash.
  • Misused priority/unbounded queues can trigger OOM or starvation.
📊

Common BlockingQueue implementations

AspectClassBest useCaveat
ArrayBlockingQueueBounded FIFO, predictable memoryFixed capacity; blocks quickly at peak
LinkedBlockingQueueHigh throughput pipelinesCan grow large if unbounded
PriorityBlockingQueuePriority-based processingUnbounded + no strict FIFO for same priority unless tie-breaker
DelayQueueScheduled/deferred tasksRequires Delayed items; no plain FIFO semantics
SynchronousQueueDirect handoff, zero bufferingProducer/consumer must rendezvous exactly
🎤

Interview Q&A

🔮

Likely Follow-up Questions

  • Difference between offer(timeout) and put() for overload handling?
  • How would you add task deduplication on top of BlockingQueue?
  • When do you move from in-JVM queue to Kafka/RabbitMQ?
🧾

Quick Cheat Sheet

TypeIn-memory, thread-safe, blocking queue (JVM-local).
Key opsput() blocks on full, take() blocks on empty.
Default pickArrayBlockingQueue (bounded) for safer memory control.
Production must-haveQueue depth + wait-time metrics + interrupt-safe code.
🔗

Related Topics