Skip to main content
  1. Java Concurrency (java.util.concurrent)/

LinkedBlockingQueue

2 mins

LinkedBlockingQueue is an optionally-bounded queue based on linked nodes. It is typically the default choice for producer-consumer queues because it offers higher throughput than ArrayBlockingQueue under high contention.

Source Code #

View Source on GitHub

The “Two-Lock Queue” Algorithm #

One of the most important aspects of LinkedBlockingQueue is its use of two separate locks for insertion and removal. This is a variant of the “two-lock queue” algorithm, which allows a producer and a consumer to operate concurrently.

private final ReentrantLock putLock = new ReentrantLock();
private final Condition notFull = putLock.newCondition();

private final ReentrantLock takeLock = new ReentrantLock();
private final Condition notEmpty = takeLock.newCondition();

private final AtomicInteger count = new AtomicInteger();

Because of the dual-lock mechanism, a producer can insert an element while a consumer is concurrently removing a different element. This significantly increases throughput compared to the single-lock ArrayBlockingQueue.

Canonical Usage #

When to use: Use LinkedBlockingQueue when you need a high-performance, optionally-bounded queue for producer-consumer scenarios. It is the default queue for Executors.newFixedThreadPool().

Common Patterns:

  • Default Unbounded Work Queue: Use the default constructor (new LinkedBlockingQueue<>()) for an unbounded queue (Integer.MAX_VALUE). This is often safer than ArrayBlockingQueue as it grows as needed.
  • Bounded Capacity: Always provide a capacity bound when the producer might outpace the consumer indefinitely, to prevent OutOfMemoryError.
// Default (unbounded) queue
BlockingQueue<Runnable> queue = new LinkedBlockingQueue<>();

// Bounded queue with 5000 slots
BlockingQueue<String> messages = new LinkedBlockingQueue<>(5000);

Performance Trade-offs #

  • Pros: Dual-lock mechanism allows parallel put/take. Generally higher throughput on multi-core systems.
  • Cons: Every insertion allocates a new Node object, which increases pressure on the Garbage Collector (GC).