Examples of DelayQueue in Java

In this post we will discuss about DelayQueue and how to make use of DelayQueue class. DelayQueue is a special type of BlockingQueue which allows elements to be retrieved in order of their finishing delay times i.e. an element whose delay time finishes first is retrieved first from DelayQueue.

The DelayQueue is backed by a heap. In  DelayQueue implementation the BlockingQueue methods are implemented in such a way that only delay expired elements can be taken out of the queue. As an example if the delay has not expired for any elements in the queue then the poll method will return null on the other hand if multiple elements have expired delays, then the element with the longest delay expiration will be taken first.

Expiration occurs when an element's getDelay(TimeUnit.NANOSECONDS) method returns a value less than or equal to zero. Even though unexpired elements cannot be removed using take or poll, they are otherwise treated as normal elements. For example, the size method returns the count of both expired and unexpired elements. This queue does not permit null elements.

Following are the ways to create a DelayQueue :

//Creates a new DelayQueue that is initially empty.
DelayQueue()
//Creates a DelayQueue initially containing the elements of the given collection of Delayed instances.
DelayQueue(Collection  c)

DelayQueue Behaviours:

  1. DelayQueue is an unbounded queue. It extends Delayed interface.
  2. An element from DelayQueue can only be taken when its delay has expired and If no delay has expired then there is no head and poll will return null. If multiple   elements have expired delays, then the element with the longest delay expiration will be taken first.
  3. DelayQueue doesn’t permit Null element.
  4. For the expiry based DelayQueue to work, elements stored in DelayQueue should implement the Delayed interface:        
package java.util.concurrent;

public interface Delayed extends Comparable {
   long getDelay(TimeUnit unit);
}

This interface forces my object to implement 2 methods:

getDelay : Returns the remaining delay associated with this object, in the given time unit. An element will be dequeued from queue if getDelay() method returns a value less than or equal to zero.”

compareTo : The Delayed interface extends the Comparable interface, so Delayed implementations must override the compareTo() to specify how they should be ordered with respect to other Delayed objects.

Real life use case of DelayQueue :

There are some mail client which sends a mail to recipients after certain delay. Consider the scenario,after clicking on the send mail button you have realized that you missed some important content to write / forgot to add someone important in the mail chain. So here each outgoing mail can be added in DelayQueue with a specific delay time, after expiration the mail will be be originally sent to recipients. Let us check the example:

In the implementation class Email of the Delayed interface, we have to implement the getDelay and the compareTo methods.

Email.java

package com.tuturself.pc;

import java.util.concurrent.Delayed;
import java.util.concurrent.TimeUnit;

/**
 * @author Ninja Panda
 */
public class Email implements Delayed {

 private String receipient;
 private String mailBody;
 private long startTime;

 public Email(String receipient, String body, long delay) {
  this.receipient = receipient;
  this.mailBody = body;
  this.startTime = System.currentTimeMillis() + delay;
 }

 @Override
 public long getDelay(TimeUnit unit) {
  long diff = startTime - System.currentTimeMillis();
  return unit.convert(diff, TimeUnit.MILLISECONDS);
 }

 @Override
 public int compareTo(Delayed o) {
  if (this.startTime < ((Email) o).startTime) {
   return -1;
  }
  if (this.startTime > ((Email) o).startTime) {
   return 1;
  }
  return 0;
 }

 @Override
 public String toString() {
  return "Email [receipient=" + receipient + ", mailBody=" + mailBody + ", startTime=" + startTime + "]";
 }
}

DelayQueueProducer.java:

In DelayQueueProducer, we are creating a Email object with its attributes and pushed it to our DelayQueue.

package com.tuturself.pc;

import java.util.Random;
import java.util.UUID;
import java.util.concurrent.BlockingQueue;

public class DelayQueueProducer {

 private BlockingQueue queue;
 private final Random random = new Random();

 private static final String emailBody = "Email body text with delay :: ";

 public DelayQueueProducer(BlockingQueue queue) {
  super();
  this.queue = queue;
 }

 private Thread producerThread = new Thread(new Runnable() {
  @Override
  public void run() {
   while (true) {
    try {

     // Put Random delay for each email to send.
     int delay = random.nextInt(10000);
     String receipient = UUID.randomUUID().toString() + "@gmail.com";
     Email email = new Email(receipient, emailBody + delay, delay);

     System.out.printf("Put emial in a DelayQueue = %s%n", email);
     queue.put(email);
     Thread.sleep(500);
    } catch (InterruptedException e) {
     e.printStackTrace();
    }
   }
  }
 }, "Producer Thread");

 public void start() {
  this.producerThread.start();
 }
}

DelayQueueConsumer.java :

In DelayQueueConsumer, it tries to find the email that has expired the delay and takes them from the queue and send the email to the recipient list, if it could not, it waits until an element will be put and expired.

package com.tuturself.pc;

import java.util.concurrent.BlockingQueue;

public class DelayQueueConsumer {

 private String name;
 private BlockingQueue queue;

 public DelayQueueConsumer(String name, BlockingQueue queue) {
  super();
  this.name = name;
  this.queue = queue;
 }

 private Thread consumerThread = new Thread(new Runnable() {
  @Override
  public void run() {
   while (true) {
    try {
     // Take the email out from the DelayQueue object and send the mail
     Email emial = (Email) queue.take();
     System.out.printf("[%s] - Sending mail when delay is over = %s%n", Thread.currentThread()
      .getName(), emial);
     Thread.sleep(1000);
    } catch (InterruptedException e) {
     e.printStackTrace();
    }
   }
  }
 });

 public void start() {
  this.consumerThread.setName(name);
  this.consumerThread.start();
 }

}

DelayQueueTest.java :

Finally, we are running the DelayQueueTest where we are creating a new DelayQueue of Email Object and starting a new DelayQueueProducer then we let our new DelayQueueConsumer to take and print the expired emails.

package com.tuturself.pc;

import java.util.concurrent.BlockingQueue;
import java.util.concurrent.DelayQueue;

public class DelayQueueTest {

 public static void main(String[] args) throws InterruptedException {
  // Creates an instance of blocking queue using the DelayQueue.
  BlockingQueue queue = new DelayQueue();

  // Starting DelayQueue Producer to push some delayed objects to the queue
  new DelayQueueProducer(queue).start();

  // Starting DelayQueue Consumer to take the expired delayed objects from the
  // queue
  new DelayQueueConsumer("Consumer Thread-1", queue).start();
 }
}

Output :

Put emial in a DelayQueue = Email [[email protected], mailBody=Email body text with delay :: 7628, startTime=1483007429938]
Put emial in a DelayQueue = Email [[email protected], mailBody=Email body text with delay :: 8837, startTime=1483007431651]
Put emial in a DelayQueue = Email [[email protected], mailBody=Email body text with delay :: 5507, startTime=1483007428821]
Put emial in a DelayQueue = Email [[email protected], mailBody=Email body text with delay :: 595, startTime=1483007424409]
Put emial in a DelayQueue = Email [[email protected], mailBody=Email body text with delay :: 3984, startTime=1483007428299]
[Consumer Thread-1] - Sending mail when delay is over = Email [[email protected], mailBody=Email body text with delay :: 595, startTime=1483007424409]
Put emial in a DelayQueue = Email [[email protected], mailBody=Email body text with delay :: 3504, startTime=1483007428319]
Put emial in a DelayQueue = Email [[email protected], mailBody=Email body text with delay :: 2773, startTime=1483007428089]
Put emial in a DelayQueue = Email [[email protected], mailBody=Email body text with delay :: 6161, startTime=1483007431978]
Put emial in a DelayQueue = Email [[email protected], mailBody=Email body text with delay :: 9027, startTime=1483007435344]
Put emial in a DelayQueue = Email [[email protected], mailBody=Email body text with delay :: 3959, startTime=1483007430777]
Put emial in a DelayQueue = Email [[email protected], mailBody=Email body text with delay :: 6372, startTime=1483007433690]
Put emial in a DelayQueue = Email [[email protected], mailBody=Email body text with delay :: 8851, startTime=1483007436669]
[Consumer Thread-1] - Sending mail when delay is over = Email [[email protected], mailBody=Email body text with delay :: 2773, startTime=1483007428089]
Put emial in a DelayQueue = Email [[email protected], mailBody=Email body text with delay :: 2090, startTime=1483007430409]
Put emial in a DelayQueue = Email [[email protected], mailBody=Email body text with delay :: 7792, startTime=1483007436612]
[Consumer Thread-1] - Sending mail when delay is over = Email [[email protected], mailBody=Email body text with delay :: 3984, startTime=1483007428299]
Put emial in a DelayQueue = Email [[email protected], mailBody=Email body text with delay :: 8001, startTime=1483007437321]
Put emial in a DelayQueue = Email [[email protected], mailBody=Email body text with delay :: 2936, startTime=1483007432757]
[Consumer Thread-1] - Sending mail when delay is over = Email [[email protected], mailBody=Email body text with delay :: 3504, startTime=1483007428319]
Put emial in a DelayQueue = Email [[email protected], mailBody=Email body text with delay :: 5307, startTime=1483007435629]
Put emial in a DelayQueue = Email [[email protected], mailBody=Email body text with delay :: 3366, startTime=1483007434188]
[Consumer Thread-1] - Sending mail when delay is over = Email [receipient=241f4147-0b0f-4[email protected], mailBody=Email body text with delay :: 5507, startTime=1483007428821]
Put emial in a DelayQueue = Email [[email protected], mailBody=Email body text with delay :: 1157, startTime=1483007432480]
Put emial in a DelayQueue = Email [[email protected], mailBody=Email body text with delay :: 8376, startTime=1483007440200]
[Consumer Thread-1] - Sending mail when delay is over = Email [[email protected], mailBody=Email body text with delay :: 7628, startTime=1483007429938]
Put emial in a DelayQueue = Email [[email protected], mailBody=Email body text with delay :: 8593, startTime=1483007440917]
Put emial in a DelayQueue = Email [[email protected], mailBody=Email body text with delay :: 9441, startTime=1483007442265]
[Consumer Thread-1] - Sending mail when delay is over = Email [[email protected], mailBody=Email body text with delay :: 2090, startTime=1483007430409]
Put emial in a DelayQueue = Email [[email protected], mailBody=Email body text with delay :: 1585, startTime=1483007434909]
Put emial in a DelayQueue = Email [[email protected], mailBody=Email body text with delay :: 5753, startTime=1483007439578]
[Consumer Thread-1] - Sending mail when delay is over = Email [[email protected], mailBody=Email body text with delay :: 3959, startTime=1483007430777]
Put emial in a DelayQueue = Email [[email protected], mailBody=Email body text with delay :: 1183, startTime=1483007435509]
Put emial in a DelayQueue = Email [[email protected], mailBody=Email body text with delay :: 5892, startTime=1483007440719]
[Consumer Thread-1] - Sending mail when delay is over = Email [[email protected], mailBody=Email body text with delay :: 8837, startTime=1483007431651]
Put emial in a DelayQueue = Email [[email protected], mailBody=Email body text with delay :: 3350, startTime=1483007438677]
Put emial in a DelayQueue = Email [[email protected], mailBody=Email body text with delay :: 395, startTime=1483007436222]
[Consumer Thread-1] - Sending mail when delay is over = Email [[email protected], mailBody=Email body text with delay :: 6161, startTime=1483007431978]
Put emial in a DelayQueue = Email [[email protected], mailBody=Email body text with delay :: 192, startTime=1483007436520]

 

core java 12 Java Concurrent Packages 12

FOLLOW US ON LinkedIn



Explore Tutu'rself