Deep Dive into Java’s SynchronousQueue: How It Works and Its Implementation
This article provides a comprehensive analysis of Java's SynchronousQueue, detailing its unique zero-capacity behavior, differences from other BlockingQueue implementations, internal structures such as TransferQueue and TransferStack, fair and non‑fair modes, and the core transfer algorithm with code examples.
SynchronousQueue Overview
SynchronousQueue is a special BlockingQueue with zero capacity, meaning each put operation must wait for a corresponding take operation. It differs from other BlockingQueues because it does not store elements and methods like peek, contains, clear, and isEmpty are effectively no‑ops.
Key Characteristics
SynchronousQueue has no capacity; put and take must occur simultaneously.
Methods like peek, contains, clear, and isEmpty are ineffective.
Supports both fair (FIFO) and non‑fair (LIFO) ordering.
Internally uses TransferQueue for fair mode and TransferStack for non‑fair mode.
Implementation Details
Class Definition
public class SynchronousQueue<E> extends AbstractQueue<E> implements BlockingQueue<E>, java.io.Serializable {Constructors
public SynchronousQueue() { this(false); }
public SynchronousQueue(boolean fair) { this.fair = fair; }TransferQueue (Fair Mode)
static final class TransferQueue<E> extends Transferer<E> { ... }TransferQueue maintains a dummy node, head, tail, and uses CAS operations to enqueue and match nodes. The transfer method handles both put (data) and take (request) operations, advancing the tail and head as needed.
TransferStack (Non‑Fair Mode)
static final class TransferStack<E> extends Transferer<E> { ... }TransferStack uses a stack of nodes with three states: REQUEST, DATA, and FULFILLING. Nodes are pushed and popped using CAS, and matching is performed by linking complementary nodes.
Transfer Method
The core transfer algorithm decides whether to enqueue a new node or match with an existing one, handling timeouts, interruptions, and cancellation. It works for both fair and non‑fair modes.
awaitFulfill
Object awaitFulfill(QNode s, E e, boolean timed, long nanos) { ... }This method spins or blocks the thread until the node is matched, cancelled, timed out, or interrupted.
Cancellation
void tryCancel(Object cmp) { UNSAFE.compareAndSwapObject(this, itemOffset, cmp, this); }Cancellation marks a node as cancelled by setting its item field to itself.
Cleaning Up Nodes
void clean(QNode pred, QNode s) { ... }The clean method removes cancelled nodes from the queue or stack, advancing head and tail pointers as necessary.
Conclusion
The SynchronousQueue implementation is complex, involving low‑level CAS operations, spin‑wait loops, and careful handling of fairness policies. Understanding its internal mechanisms helps developers appreciate the performance characteristics of concurrent data structures in Java.
Signed-in readers can open the original source through BestHub's protected redirect.
This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactand we will review it promptly.
Programmer DD
A tinkering programmer and author of "Spring Cloud Microservices in Action"
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.
