LinkedBlockingQueue
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 #
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 thanArrayBlockingQueueas 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
Nodeobject, which increases pressure on the Garbage Collector (GC).