SynchronousQueue transfers an element directly between a producer and a waiting consumer; it does not retain elements in an internal queue.
Java SynchronousQueue: a handoff has no storage capacity
Observe the zero-capacity contract
An immediate offer fails when no consumer is ready. A subsequent put waits until a consumer accepts the value. The fixture starts the consumer only after the failed offer, then joins it before printing the received shipment ID.
This handoff can apply backpressure, but a stalled consumer can hold the producer indefinitely. Use a timed offer or cancellation where the caller has a deadline. Buffered blocking queues decouple arrival and consumption up to their configured capacity.
Separate transfer from processing
A successful put means the consumer accepted the element; it does not prove that the consumer completed its business work. If acknowledgment matters, pair the transfer with a separate completion signal or durable result record.
Working program
import java.util.concurrent.SynchronousQueue;
import java.util.concurrent.atomic.AtomicReference;
public class ShipmentDirectHandoff {
public static void main(String[] args) throws InterruptedException {
SynchronousQueue<String> handoff = new SynchronousQueue<>();
System.out.println("immediate=" + handoff.offer("lot-47"));
AtomicReference<String> received = new AtomicReference<>();
Thread receiver = new Thread(() -> {
try { received.set(handoff.take()); }
catch (InterruptedException stopped) { Thread.currentThread().interrupt(); }
});
receiver.start();
handoff.put("lot-82");
receiver.join();
System.out.println("received=" + received.get());
}
}Output
immediate=false
received=lot-82Cost and ownership
The queue itself has no element capacity, although producer and consumer tasks still occupy threads or other runtime resources. Transfer can block; its latency is governed by consumer readiness, not a queue traversal cost.
Common Mistakes
- Do not assume offer stores work when no consumer exists.
- Do not treat a completed put as proof that processing completed.
- Do not use unbounded waits when the request has a deadline.
Read next
Java blocking queues: bounded capacity and backpressure, Java BlockingQueue drainTo: batch size is not a transaction, Java cancellation: timed waits and cooperative interruption, Java ConcurrentLinkedQueue: size is not an admission limit.
Continue with: Java Exchanger: swap buffers at a two-party rendezvous, Java LinkedTransferQueue: wait until a consumer receives work.
