Question 9 · Section 4

What is Queue and what implementations exist?

4. ConcurrentLinkedQueue — lock-free 5. BlockingQueue — Producer-Consumer 6. null forbidden in most queues 7. SynchronousQueue — for direct handoff

Language versions: English Russian Ukrainian

🟢 Junior Level

Queue — data structure following FIFO principle (First In, First Out).

Simple analogy: Queue at a store. First come, first served.

Main methods:

Action Exception Safe method
Add add(e) offer(e)
Retrieve remove() poll()
Peek element() peek()
Queue<String> queue = new ArrayDeque<>();

queue.offer("A");  // Added
queue.offer("B");

String first = queue.poll();  // → "A" (first left)
String next = queue.peek();   // → "B" (peeked)

offer/poll/peek preferred in production code because they don’t throw exceptions — return false/null on error, allowing graceful handling.


🟡 Middle Level

Main implementations

ArrayDeque:

// Circular array → O(1) insertion/removal
Queue<String> queue = new ArrayDeque<>();
queue.offer("A");  // Fast
queue.poll();      // Fast

PriorityQueue:

// Binary Heap → extract by priority
Queue<Integer> pq = new PriorityQueue<>();
pq.offer(5);
pq.offer(1);
pq.offer(3);
pq.poll();  // → 1 (smallest!)

Methods: Exception vs Special Value

// Throw exception:
queue.add(e);     // IllegalStateException if full
queue.remove();   // NoSuchElementException if empty
queue.element();  // NoSuchElementException if empty

// Return special value:
queue.offer(e);   // false if full
queue.poll();     // null if empty
queue.peek();     // null if empty

// ✅ In production use offer/poll/peek!

Thread-safe queues

// Lock-free (high throughput)
Queue<String> q = new ConcurrentLinkedQueue<>();

// Blocking (Producer-Consumer)
BlockingQueue<String> q = new LinkedBlockingQueue<>();
q.put("A");       // Blocks if full
String e = q.take();  // Blocks if empty

// Bounded (memory control)
BlockingQueue<String> q = new ArrayBlockingQueue<>(100);
// → Max 100 elements → OOM protection

🔴 Senior Level

When NOT to use Queue

  1. If random access needed — use List
  2. If uniqueness needed — use Set
  3. If data needs sorting — PriorityQueue with comparator or TreeSet

Why queues don’t like null?

// Most queues forbid null
queue.offer(null);  // → NullPointerException!

// Why?
// poll() and peek() return null for empty queue
// If null is valid element → ambiguity!
// → "queue empty" or "null at head"?

BlockingQueue patterns

// Producer-Consumer
BlockingQueue<Task> queue = new LinkedBlockingQueue<>(1000);

// Producer
queue.put(task);  // Blocks if full → backpressure!

**Backpressure**  mechanism where slow consumer signals fast producer to slow down. Bounded Queue blocks producer until consumer frees space.

// Consumer
Task task = queue.take();  // Blocks if empty

SynchronousQueue

// Zero capacity queue!
BlockingQueue<String> q = new SynchronousQueue<>();

// put blocks until someone does take
// Block = thread "sleeps" and doesn't consume CPU until another thread takes element. Effective for synchronization without busy-wait.
q.put("A");  // Waiting...

// In another thread:
String s = q.take();  // → "A", put unblocks

// Usage: Executors.newCachedThreadPool()

DelayQueue

// Elements available only after delay
class DelayedTask implements Delayed {
    private final long deadline;

    public long getDelay(TimeUnit unit) {
        return unit.convert(deadline - System.currentTimeMillis(), MILLISECONDS);
    }
}

DelayQueue<DelayedTask> queue = new DelayQueue<>();
// poll() returns element only when getDelay() <= 0

TransferQueue (Java 7+)

// Producer waits until Consumer takes element
TransferQueue<String> q = new LinkedTransferQueue<>();

// Producer
q.transfer("message");  // Blocks until consumer takes!

// Consumer
String msg = q.take();  // Takes, producer unblocks

// Usage: synchronous data transfer
// Synchronous transfer = producer waits for exact moment when consumer *accepts* element (not just puts in buffer). Analogy: handing file person-to-person vs leaving in mailbox.

Production Experience

Real case: Bounded Queue saved from OOM

  • Producer faster than Consumer → queue growing
  • Unbounded Queue → OOM in 2 hours
  • Solution: ArrayBlockingQueue(10000)
  • Result: Producer blocks → stable system

Best Practices

  1. offer/poll/peek instead of add/remove/element
  2. ArrayDeque — for single-thread
  3. Bounded Queue — for backpressure
  4. ConcurrentLinkedQueue — lock-free
  5. BlockingQueue — Producer-Consumer
  6. null forbidden in most queues
  7. SynchronousQueue — for direct handoff

Summary for Senior

  • Queue = FIFO, offer/poll/peek preferred
  • ArrayDeque — fastest single-thread
  • BlockingQueue — Producer-Consumer with backpressure
  • Bounded — OOM protection
  • ConcurrentLinkedQueue — lock-free
  • TransferQueue — synchronous handoff
  • null forbidden (ambiguity with poll)

🎯 Interview Cheat Sheet

Must know:

  • Queue = FIFO (First In, First Out), methods: offer/poll/peek preferred over add/remove/element
  • offer/poll/peek return false/null instead of exception — safer for production
  • ArrayDeque — fastest single-thread (circular array, O(1) insertion/removal)
  • PriorityQueue = Binary Heap, extract by priority (smallest element), O(log n)
  • BlockingQueue = Producer-Consumer pattern, put/take block, bounded queue = backpressure
  • SynchronousQueue = zero capacity, producer blocks until consumer takes element
  • TransferQueue (Java 7+) — synchronous handoff: transfer() blocks until consumer takes
  • null forbidden in most queues — ambiguity with poll() returning null

Common follow-up questions:

  • Why offer/poll/peek better than add/remove/element? — Don’t throw exceptions, allow graceful handling
  • Why bounded queue? — Backpressure: slow consumer blocks fast producer, OOM protection
  • How SynchronousQueue differs from regular queue? — Zero capacity, put blocks until someone does take
  • When to use TransferQueue? — For synchronous data transfer, producer waits for exact acceptance moment

Red flags (NOT to say):

  • ❌ “Queue allows storing null” — most implementations forbid null (ambiguity with poll)
  • ❌ “Unbounded Queue — decent choice for production” — without bounded queue risk OOM from fast producer
  • ❌ “add/remove/element — best choice” — they throw exceptions, offer/poll/peek safer
  • ❌ “PriorityQueue extracts largest element” — by default extracts SMALLEST (need reverse Comparator for largest)

Related topics:

  • [[What are the main Collection Framework interfaces]]
  • [[What is Deque]]
  • [[What is the difference between List, Set and Queue]]
  • [[What is Stack]]