Java - Collection Framework Transfer Queues

Introduction

TransferQueue represents a transfer queue.

In a TransferQueue, a producer will wait to hand off an element to a consumer.

This is a useful for a message passing application, where a producer makes sure that its message has been consumed by a consumer.

A producer hands off an element to a consumer using the transfer(E element) method of the TransferQueue.

When a producer invokes this method, it waits until a consumer takes its element.

If the TransferQueue has more than one element, all its elements must be consumed.

The tryTransfer() method provides a non-blocking and a timeout version of the method.

TransferQueue getWaitingConsumerCount() method returns the number of waiting consumers.

hasWaitingConsumer() method returns true if there is a waiting consumer; otherwise, it returns false.

LinkedTransferQueue is an implementation class for the TransferQueue interface.

The following code creates DataProducer class whose instance represents a producer for a TransferQueue.

Demo

import java.util.Random;
import java.util.concurrent.LinkedTransferQueue;
import java.util.concurrent.TransferQueue;
import java.util.concurrent.atomic.AtomicInteger;

class DataProducer extends Thread {
  private final String name;
  private final TransferQueue<Integer> tQueue;
  private final AtomicInteger sequence;

  public DataProducer(String name, TransferQueue<Integer> tQueue,
      AtomicInteger sequence) {// w w w  .  j  a v a  2s.  c o m
    this.name = name;
    this.tQueue = tQueue;
    this.sequence = sequence;
  }

  @Override
  public void run() {
    while (true) {
      try {
        int sleepTime = 3;
        Thread.sleep(sleepTime * 1000);
        int nextNum = this.sequence.incrementAndGet();
        if (nextNum % 2 == 0) {
          System.out.format("%s: Enqueuing: %d%n", name, nextNum);
          tQueue.put(nextNum); // Enqueue
        } else {
          System.out.format("%s: Handing off: %d%n", name, nextNum);
          System.out.format("%s: has a waiting consumer: %b%n", name,
              tQueue.hasWaitingConsumer());
          tQueue.transfer(nextNum); // A hand off
        }
      } catch (InterruptedException e) {
        e.printStackTrace();
      }
    }
  }
}

class TQConsumer extends Thread {
  private final String name;
  private final TransferQueue<Integer> tQueue;
  private final Random rand = new Random();

  public TQConsumer(String name, TransferQueue<Integer> tQueue) {
    this.name = name;
    this.tQueue = tQueue;
  }

  @Override
  public void run() {
    while (true) {
      try {
        // Sleep for 1 to 5 random number of seconds
        int sleepTime = rand.nextInt(5) + 1;
        Thread.sleep(sleepTime * 1000);

        int item = tQueue.take();
        System.out.format("%s removed: %d%n", name, item);
      } catch (InterruptedException e) {
        e.printStackTrace();
      }
    }
  }
}

public class Main {
  public static void main(String[] args) {
    final TransferQueue<Integer> tQueue = new LinkedTransferQueue<>();
    final AtomicInteger sequence = new AtomicInteger();

    // Initialize transfer queue with five items
    for (int i = 0; i < 5; i++) {
      try {
        tQueue.put(sequence.incrementAndGet());
      } catch (InterruptedException e) {
        e.printStackTrace();
      }
    }

    System.out.println("Initial queue: " + tQueue);

    // Create and start a producer and a consumer
    new DataProducer("Producer-1", tQueue, sequence).start();
    new TQConsumer("Consumer-1", tQueue).start();
  }
}

Result