Wednesday, 30 March 2016

DelayQueue in Java

DelayQueue which is an implementation of BlockingQueue interface is added in Java 5 along with other concurrent utilities like CyclicBarrier, Exchanger, ConcurentSkipListMap, CopyOnWriteArraySet etc.

DelayQueue is an unbounded implementation of BlockingQueue, that's where it is different from the other implementation of BlockingQueue like ArrayBlockingQueue (Always bounded) and LinkedBlockingQueue (both bounded and unbounded options). Though it is similar to PriorityBlockingQueue in this behaviour as PriorityBlockingQueue is also unbounded.

DelayQueue stores Delayed elements

DelayQueue is a special implementation of blocking queue as it can only store elements of type Delayed and an element can only be retrieved from DelayQueue when its delay has expired.

Delayed interface which defines the type for the elements in the DelayQueue has one method

  • getDelay(TimeUnit unit) - Returns the remaining delay associated with this object, in the given time unit.

Delayed interface also extends Comparable interface so compareTo(T o) method should also be implemented. This method implementation will decide whether you want to retrieve elements in ascending order of delay or descending.

According to JavaDocs "An implementation of this interface must define a compareTo method that provides an ordering consistent with its getDelay method."

So, just to sum it up; DelayQueue stores elements of type Delayed. When you implement Delayed interface two methods have to be implemented getDelay(TimeUnit unit) and compareTo(T o).

Example Code

Let's create a producer consumer using the DelayQueue. There is also a class DelayClass which implements Delayed interface. DelayQueue will store objects of DelayClass.

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

public class DelayQDemo {

    public static void main(String[] args) {
        // delay of 2 seconds
        final long delay = 2000;
        BlockingQueue<DelayClass> delayQ = new DelayQueue<DelayClass>();
        
        // Producer thread
        new Thread(){
            @Override
            public void run() {
                for(int i = 0; i < 5; i++){
                    try {
                        // putting elements in delay queue
                        delayQ.put(new DelayClass("item"+i, delay));
                        Thread.sleep(50);
                    } catch (InterruptedException e) {
                        System.out.println("Error while putting values in the Queue " + e.getMessage());
                    }
                }
            }
        }.start();
        
        // Consumer thread
        new Thread(){
            @Override
            public void run() {
                for(int i = 0; i < 5; i++){
                    try {
                        // retrieving elements from delay queue
                        System.out.println(" Consumer got - " + delayQ.take());
                        Thread.sleep(500);
                    } catch (InterruptedException e) {
                        System.out.println("Error while retrieving value from the Queue " + e.getMessage());
                    }
                }
            }
        }.start();
    }

}

// Delayed interface implementing class
class DelayClass implements Delayed{
    private String item;
    private long expireTime;
    DelayClass(String item, long delay){
        this.item = item;
        // Expiretime is currenttime+delay, so if delay of 2 sec is required
        // expiration from queue will hppn after
        // currenttime + 2 sec
        this.expireTime = System.currentTimeMillis() + delay;
    }
    
    @Override
    public long getDelay(TimeUnit unit) {
        long diff = expireTime - System.currentTimeMillis();
        return unit.convert(diff, TimeUnit.MILLISECONDS);
    }
    
    @Override
    public int compareTo(Delayed o) {
        if(this.getDelay(TimeUnit.MILLISECONDS) < o.getDelay(TimeUnit.MILLISECONDS)){
            return -1;
        }
        if(this.getDelay(TimeUnit.MILLISECONDS) > o.getDelay(TimeUnit.MILLISECONDS)){
            return 1;
        }
        return 0;
            
    }
    
    public String toString(){
        return "item = " + item + " expireTime = " + expireTime;
    } 
}

Output

Consumer got - item = item0 expireTime = 1458998017469
Consumer got - item = item1 expireTime = 1458998017531
Consumer got - item = item2 expireTime = 1458998017594
Consumer got - item = item3 expireTime = 1458998017656
Consumer got - item = item4 expireTime = 1458998017719

Here it can be seen elements are retrieved from the queue only after the delay expires.

Points to remember

  1. DelayQueue stores element of type Delayed.
  2. Element is retrieved from DelayQueue only when its delay has expired.
  3. The head of the queue is thatDelayed element whose delay expired furthest in the past.
  4. If no delay has expired there is no head and poll will return null.
  5. Expiration occurs when an element's getDelay(TimeUnit tu) method returns a value less than or equal to zero.

Source : https://docs.oracle.com/javase/8/docs/api/java/util/concurrent/DelayQueue.html

That's all for this topic DelayQueue in Java. If you have any doubt or any suggestions to make please drop a comment. Thanks!


Related Topics

  1. SynchronousQueue in Java
  2. BlockingDeque in Java Concurrency
  3. ConcurrentHashMap in Java
  4. ReentrantReadWriteLock in Java
  5. Semaphore in Java concurrency
  6. Java Concurrency interview questions

You may also like -

No comments:

Post a Comment