skip to content

What is java.util.concurrent.Exchanger and when would you use it?

level: middleimportance: nice to knowfreq 18%

answer

  1. Rendezvous for exactly two threads
  2. exchange(x) blocks until partner, then swap
  3. Bidirectional vs SynchronousQueue one-way
  4. Buffer-swap pipeline, recycle allocations
  5. Timed overload throws TimeoutException

basics

~10 s

Exchanger is a meeting point where exactly two threads swap objects. Each thread calls exchange(myValue); both block until the partner arrives, then each receives what the other passed in.

solid answer

~40 s

Exchanger<V> is a synchronization point for exactly two threads. When a thread calls exchange(v), it blocks until a second thread also calls exchange on the same Exchanger; then the two swap: each returns the value the other handed in. It is a bidirectional rendezvous, unlike a one-way handoff (SynchronousQueue) or a one-to-many barrier. The classic use is a buffer-swapping pipeline: a producer fills a buffer while a consumer drains another, and at the rendezvous they trade buffers, recycling allocations. exchange() is interruptible and there is a timed overload exchange(v, timeout, unit) that throws TimeoutException. It only ever pairs two threads at a time; if three call it, two pair up and the third waits for a fourth. Throughput-wise it is cheaper than a queue for the pure two-thread swap case.

code

java · 16 lines
java
Exchanger<List<String>> exchanger = new Exchanger<>();

// Producer thread
List<String> buffer = new ArrayList<>();
while (running) {
    fill(buffer);                 // fill my buffer
    buffer = exchanger.exchange(buffer); // hand it over, get an empty one back
}

// Consumer thread
List<String> buffer = new ArrayList<>();
while (running) {
    process(buffer);              // drain my buffer
    buffer.clear();
    buffer = exchanger.exchange(buffer); // hand the empty one over, get a full one
}

go deeper

for a junior

Knows Exchanger lets two threads swap objects and that exchange() blocks until both arrive.

for a middle

Can implement a producer/consumer buffer-swap, knows it is exactly two threads, and uses the timed overload to avoid blocking forever.

for a senior

Contrasts it with SynchronousQueue and barriers, explains the happens-before guarantee on the swapped object, and identifies when a plain queue is the clearer choice.

for a principal

Judges that Exchanger is a niche optimization for the symmetric two-thread swap, weighs allocation/GC benefits against readability, and steers teams to simpler queue/CompletableFuture pipelines unless the swap pattern genuinely fits.

## What problem it solves Sometimes two threads each have a piece of data and want to *trade* — each gives the other what it holds and receives what the other holds, atomically, at a single meeting point. `java.util.concurrent.Exchanger<V>` is exactly that: a **rendezvous** (a meeting point) for **exactly two** threads to **swap** objects. ## The core API - `V exchange(V x)` — A thread calls this, passing its object `x`. The call **blocks** (waits, doing nothing) until *another* thread calls `exchange` on the *same* `Exchanger` instance. At that moment the two threads **swap**: the first returns the second's object, the second returns the first's object, and both proceed. - `V exchange(V x, long timeout, TimeUnit unit)` — same, but if no partner arrives within the timeout it throws `TimeoutException`. - Both forms throw `InterruptedException` if the waiting thread is interrupted (cooperative cancellation). A generic type `V` is the type of object being swapped. `null` is a legal value to exchange. ## Why "exactly two" An `Exchanger` pairs threads two at a time. If thread A arrives first it waits; when thread B arrives, A and B pair, swap, and both leave. If a *third* thread C arrives, it does not join A and B — it waits for a *fourth* partner. So it is strictly a 1-to-1 (pairwise) construct, not a group barrier. ## Contrast with neighbours - **`SynchronousQueue`** is a *one-directional* handoff: a producer hands an item to a consumer; nothing comes back. `Exchanger` is *bidirectional* — both sides give and receive. - **`CyclicBarrier`/`Phaser`** synchronize *N* parties at a phase boundary but do not, by themselves, swap a value between a specific pair. - **A blocking queue** decouples producer and consumer in time; `Exchanger` forces them to meet at the same instant. ## The canonical use case: buffer swapping Imagine a producer that fills a buffer and a consumer that empties one. Instead of allocating a new buffer every cycle, you keep two buffers in flight. The producer fills buffer A while the consumer drains buffer B. When each finishes, they meet at the exchanger and **trade**: the producer gets the now-empty B to fill, the consumer gets the now-full A to drain. This recycles two buffers forever with zero per-cycle allocation — a classic way to reduce garbage-collection pressure in a pipeline. ## Memory visibility The exchange establishes a **happens-before** edge: writes a thread made to the object *before* calling `exchange` are visible to the partner that *receives* that object after the call returns. So you can safely mutate the buffer you hand over without extra synchronization. ## Caveats - It only ever coordinates two threads, so it does not generalize to many-party coordination. - A thread that never gets a partner blocks forever unless you use the timed overload. - It is rarely needed in modern code; queues or `CompletableFuture` pipelines usually read more clearly. It shines specifically in the symmetric two-thread buffer-swap pattern.

  • How is Exchanger different from a SynchronousQueue?
    SynchronousQueue is a one-way handoff: a put waits for a take, and only data flows producer-to-consumer. Exchanger is symmetric and bidirectional - both threads simultaneously give and receive a value, so it is a true swap rather than a handoff.
  • What happens if an odd number of threads call exchange on the same Exchanger?
    Threads pair up two at a time. The unpaired thread blocks (or times out with the timed overload) waiting for a partner that never arrives, so you must ensure an even number of participants or use the timeout.

Two spies meeting on a bridge to swap briefcases: each arrives, waits for the other, and at the handshake they trade simultaneously and walk away.

saying these in an interview costs you the question

  • Saying Exchanger can synchronize N threads like a barrier - it only ever pairs exactly two
  • Claiming it is one-directional like a queue - it is a symmetric swap
  • Thinking the value swap is optional - both sides always give and receive
  • Forgetting it can block forever if no partner shows up (no timeout used)

context