ConcurrentLinkedDeque in Java
ConcurrentLinkedDeque is a high-performance, thread-safe, non-blocking, unbounded double-ended queue in Java.
It belongs to the java.util.concurrent package and is used when multiple threads must insert or remove elements from both ends without locking.
It is one of the most scalable concurrent data structures in Java.
What Is ConcurrentLinkedDeque?
A ConcurrentLinkedDeque is:
- Thread-safe (for multi-threaded use)
- Lock-free (uses CAS operations)
- Unbounded (grows automatically)
- Allows operations at head + tail
- Ideal for work-stealing & task scheduling
- Internally uses linked nodes
- Provides weakly consistent iterators
It implements:
- Deque
- Queue
Compared to ConcurrentLinkedQueue, this deque supports double-ended operations.
Internal Working of ConcurrentLinkedDeque
1. Linked Nodes
Each element is stored in a node containing:
prevpointernextpointer
It behaves like a thread-safe doubly linked list.
2. Lock-Free with CAS
All operations (add/remove) use CAS – Compare-And-Swap, so:
- No thread blocking
- No locking
- Very high concurrency
- Low latency
Multiple threads can operate simultaneously on both ends.
Key Features of ConcurrentLinkedDeque
1. Thread-Safe
Designed for multi-threaded usage.
2. Lock-Free Performance
No synchronized blocks → extremely fast.
3. Double-Ended
Supports:
addFirst(),pollFirst()addLast(),pollLast()
4. Unbounded
Automatically expands as needed.
5. Weakly Consistent Iterator
- Does NOT throw
ConcurrentModificationException - Reflects updates during iteration
- Never freezes while other threads update
6. Highly Scalable
Excellent for concurrent task processing.
Common Methods of ConcurrentLinkedDeque
Adding Elements
| Method | Description |
|---|---|
addFirst(e) | Insert at head |
addLast(e) | Insert at tail |
offerFirst(e) | Add at head (non-throwing) |
offerLast(e) | Add at tail |
Removing Elements
| Method | Description |
|---|---|
pollFirst() | Remove & return head |
pollLast() | Remove & return tail |
removeFirst() | Throw exception if empty |
removeLast() | Throw exception if empty |
Peeking Elements
| Method | Description |
|---|---|
peekFirst() | View head |
peekLast() | View tail |
peek() | Same as peekFirst |
Other Methods
isEmpty()iterator()descendingIterator()size()(approximate, slow)
Simple Example: Using ConcurrentLinkedDeque
import java.util.concurrent.ConcurrentLinkedDeque;
public class Main {
public static void main(String[] args) {
ConcurrentLinkedDeque<String> deque = new ConcurrentLinkedDeque<>();
deque.addFirst("A");
deque.addLast("B");
deque.addLast("C");
System.out.println("Deque: " + deque);
System.out.println("Poll First: " + deque.pollFirst()); // A
System.out.println("Poll Last: " + deque.pollLast()); // C
System.out.println("After Poll: " + deque);
System.out.println("Peek First: " + deque.peekFirst()); // B
}
}
Output
Deque: [A, B, C]
Poll First: A
Poll Last: C
After Poll: [B]
Peek First: B
Multi-Threaded Example
import java.util.concurrent.ConcurrentLinkedDeque;
public class Demo {
public static void main(String[] args) {
ConcurrentLinkedDeque<Integer> deque = new ConcurrentLinkedDeque<>();
Runnable task = () -> {
for (int i = 1; i <= 5; i++) {
deque.offerLast(i);
}
};
Thread t1 = new Thread(task);
Thread t2 = new Thread(task);
t1.start();
t2.start();
}
}
- No locks
- No synchronization needed
- Perfect for parallel producers
When to Use ConcurrentLinkedDeque?
Use it when you need:
- Non-blocking double-ended queue
- High throughput
- Multiple producers/consumers
- Insert/remove from both ends
- Work-stealing frameworks
- Actor-based systems
- Multi-core task scheduling
Common Use Cases
- Work-stealing algorithms
- Real-time task schedulers
- Server request pipelines
- Background job processors
- Messaging/event systems
- Highly parallel applications
ConcurrentLinkedDeque vs ConcurrentLinkedQueue
| Feature | ConcurrentLinkedDeque | ConcurrentLinkedQueue |
|---|---|---|
| Ends supported | Head + Tail | Tail only |
| Structure | Double-ended | Single-ended |
| Operations | More (first/last) | Limited |
| Use Case | Work-stealing, flexible tasks | Basic producer-consumer |
| Performance | Similar | Similar |
ConcurrentLinkedDeque vs LinkedBlockingDeque
| Feature | ConcurrentLinkedDeque | LinkedBlockingDeque |
|---|---|---|
| Thread safety | Yes | Yes |
| Implementation | Lock-free | Blocking |
| Blocking ops | No | Yes (take(), put()) |
| Capacity | Unbounded | Bounded |
| Performance | Faster | Slower due to locks |
| Best for | High-speed concurrency | Producer-consumer blocking |
Advantages
- Extremely fast (lock-free)
- Thread-safe
- FIFO + LIFO both possible
- Unbounded
- Weakly consistent iterators
- Ideal for concurrent task processing
Disadvantages
- No blocking operations
size()is slow & approximate- Not suitable when capacity control is required
Points to Remember
ConcurrentLinkedDeque is the best choice when you need:
- A high-performance, lock-free deque
- Fast operations from both ends
- Maximum concurrency
- Scalable task management
- Real-time processing in multi-core systems
It is widely used in modern concurrent frameworks, high-speed servers, and parallel computing systems.
