Java - Collection Framework Delay Queues

Introduction

A DelayQueue is one of the implementation classes for the BlockingQueue interface.

It lets you implement a queue whose elements must stay in a queue for a certain amount of time.

It uses interface called Delayed to get the time an element must stay in the queue.

The interface is in the java.util.concurrent package. Its declaration is as follows:

interface Delayed extends Comparable<Delayed> {
        long getDelay(TimeUnit timeUnit);
}

The DelayQueue calls the getDelay() method of each element to know how long that element must be kept in the queue before it can be popped out.

DelayQueue will pass a TimeUnit to this method.

Your can convert the delay time of an element to the TimeUnit being passed and return the value.

To keep an element in the queue for 10 seconds, your getDelay(TimeUnit timeUnit) method will be implemented as follows:

class DelayClass implement Delayed {
        public long getDelay(TimeUnit timeUnit){
                long delay = timeUnit.convert(10, TimeUnit.SECONDS);
                return delay;
        }
}

The element stays in the DelayQueue as long as the value returned from the getDelay() method is positive.

When the return is a zero or a negative number, it is ready to get out of the queue.

You can call the take() method to take an element out of the queue.

The queue determines which one to take out by calling the compareTo() method of the elements.

This method determines the priority of an expired element.

The following code implements the Delayed interface.

It uses the DelayedJob objects as elements in a DelayQueue.

Demo

import static java.time.temporal.ChronoUnit.MILLIS;
import static java.util.concurrent.TimeUnit.MILLISECONDS;

import java.time.Instant;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.DelayQueue;
import java.util.concurrent.Delayed;
import java.util.concurrent.TimeUnit;

class DelayedJob implements Delayed {
  private final Instant scheduledTime;
  String jobName;/*from  w  w w  . j  ava  2 s . c o  m*/

  public DelayedJob(String jobName, Instant scheduledTime) {
    this.scheduledTime = scheduledTime;
    this.jobName = jobName;
  }

  @Override
  public long getDelay(TimeUnit unit) {
    long delay = MILLIS.between(Instant.now(), scheduledTime);
    long returnValue = unit.convert(delay, MILLISECONDS);
    return returnValue;
  }
  @Override
  public int compareTo(Delayed job) {
    long currentJobDelay = this.getDelay(MILLISECONDS);
    long jobDelay = job.getDelay(MILLISECONDS);

    int diff = 0;
    if (currentJobDelay > jobDelay) {
      diff = 1;
    } else if (currentJobDelay < jobDelay) {
      diff = -1;
    }
    return diff;
  }

  @Override
  public String toString() {
    String str = "(" + this.jobName + ", " + "Scheduled Time: "
        + this.scheduledTime + ")";
    return str;
  }
}

public class Main {
  public static void main(String[] args) throws InterruptedException {
    BlockingQueue<DelayedJob> queue = new DelayQueue<>();
    Instant now = Instant.now();

    // 1. Populate Data (After 3 seconds)
    // 2. Balance Data (After 6 seconds)
    // 3. Print Data (After 9 seconds)
    queue.put(new DelayedJob("Print Data", now.plusSeconds(9)));
    queue.put(new DelayedJob("Populate Data", now.plusSeconds(3)));
    queue.put(new DelayedJob("Balance Data", now.plusSeconds(6)));

    while (queue.size() > 0) {
      System.out.println("Waiting to take a job from the queue...");
      DelayedJob job = queue.take();
      System.out.println("Took Job: " + job);
    }

    System.out.println("Finished running all jobs.");
  }
}

Result