Java - Thread Exchangers

Introduction

An exchanger lets two threads wait for each other at a synchronization point.

When both threads arrive, they exchange an object and continue their activities.

Exchanger class provides an implementation for an exchanger synchronizer.

You can create an exchanger like so:

Exchanger exchanger = new Exchanger();

If you know the type of the object the threads will exchange, you can specify that using generics while creating the exchanger.

The following code creates Exchanger class to exchange String value.

Exchanger<String> exchanger = new Exchanger<String>();

Exchanger class has only one method, exchange().

When a thread is ready to exchange an object with another thread, it calls the exchange() method and waits for another thread to exchange the object.

A overloaded version of the exchange() method accepts a timeout period.

You call the exchange() method like so:

objectReceived = exchanger.exchange(objectedPassed);

Example

The following code uses an exchanger to solve a producer-consumer problem.

The producer consumer use ArrayList as buffer.

The exchanger is created as follows.

Exchanger<ArrayList<Integer>> exchangerObject = new Exchanger<ArrayList<Integer>>();

exchangerObject will let two threads exchange objects of type ArrayList<Integer>.

Demo

import java.util.ArrayList;
import java.util.Random;
import java.util.concurrent.Exchanger;

class Producer extends Thread {
  private Exchanger<ArrayList<Integer>> exchanger;
  private ArrayList<Integer> buffer = new ArrayList<Integer>();
  private int bufferLimit;
  private Random random = new Random();
  private int currentValue = 0; // to produce values

  public Producer(Exchanger<ArrayList<Integer>> exchanger,
      int bufferLimit) {
    this.exchanger = exchanger;
    this.bufferLimit = bufferLimit;
  }/*w  ww  .  j av  a 2 s.  c  om*/

  public void run() {
    while (true) {
      try {
        System.out.println("Producer is filling the buffer with data...");
        int sleepTime = random.nextInt(20) + 1;
        Thread.sleep(sleepTime * 1000);
        this.fillBuffer();
        System.out.println("Producer has produced:" + buffer);
        System.out.println("Producer is waiting to exchange the data...");
        buffer = exchanger.exchange(buffer);
      } catch (InterruptedException e) {
        e.printStackTrace();
      }
    }
  }

  public void fillBuffer() {
    for (int i = 1; i <= bufferLimit; i++) {
      buffer.add(++currentValue);
    }
  }
}

class Consumer extends Thread {
  private Exchanger<ArrayList<Integer>> exchanger;
  private ArrayList<Integer> buffer = new ArrayList<Integer>();
  private Random random = new Random();

  public Consumer(Exchanger<ArrayList<Integer>> exchanger) {
    this.exchanger = exchanger;
  }

  public void run() {
    while (true) {
      try {
        // Let's wait for the consumer to exchange data
        System.out.println("Consumer is waiting to exchange the data...");
        buffer = exchanger.exchange(buffer);
        System.out.println("Consumer has received:" + buffer);
        System.out.println("Consumer is emptying data from the buffer...");

        // Wait for some time by sleeping
        int sleepTime = random.nextInt(20) + 1;

        // Sleep for some time
        Thread.sleep(sleepTime * 1000);

        // Empty the buffer
        this.emptyBuffer();
      } catch (Exception e) {
        e.printStackTrace();
      }
    }
  }
  public void emptyBuffer() {
    buffer.clear();
  }
}

public class Main {
  public static void main(String[] args) {
    Exchanger<ArrayList<Integer>> exchanger = new Exchanger<>();
    // The producer will produce 5 integers at a time
    Producer producer = new Producer(exchanger, 5);
    Consumer consumer = new Consumer(exchanger);

    producer.start();
    consumer.start();
  }
}

Result