Nishant Lakhara
Nishant Lakhara

Reputation: 2445

DelayQueue in java - Not working as expected

I am new to concurrent programming. I created two classes as DelayedElement.java and DelayQueueExample to understand DelayQueue as follows :

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

public class DelayQueueExample {
    public static void main(String[] args) throws InterruptedException {
        DelayQueue queue = new DelayQueue();
        Delayed element1 = new DelayedElement(5);
        queue.put(element1);
        System.out.println("Put done");
        Delayed element2 = queue.take();
        System.out.println("Take done");
        System.out.println(((DelayedElement)element2).getI());
    }
}

DelayedElement class is as follows :

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

public class DelayedElement implements Delayed {

    private int i;
    public DelayedElement(int i) {
        this.setI(i);
    }

    @Override
    public int compareTo(Delayed o) {
        // TODO Auto-generated method stub
        return 0;
    }

    @Override
    public long getDelay(TimeUnit unit) {
        long diff = 10000l;
        return  unit.convert(diff, TimeUnit.MILLISECONDS);
    }

    public int getI() {
        return i;
    }

    public void setI(int i) {
        this.i = i;
    }

}

I ran the program and the output is showing that the put is done. But it is delaying infinitely when I call queue.take() operation. I have specified the delay time as 10 seconds in DelayedElement's getDeley method. So why my program is running this way? Can someone help me out to understand where I am wrong?

Upvotes: 2

Views: 1447

Answers (3)

Arun
Arun

Reputation: 327

As per javadoc of Delayed Interface getDelay(TimeUnit timeUnit) should return the remaining time of delay from the time when the element was added to the queue.

A simple way is to set the expiry time(based on the current time & dealy parameter) when the element was added to the queue and return the remaining time in expiry time when the getDelay method is called.

Implementation can be something like this

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

public class DelayedElement implements Delayed {
    private int i;
    /*
     * Expiry time in nano-seconds(more granular) 
     * i.e. time in nano seconds at which the element is added + delay converted to nanoseconds
     */
    private long expiryTime; 

    public DelayedElement(int i, int delay, TimeUnit dealyTimeUnit) {
        this.setI(i);
        expiryTime = TimeUnit.NANOSECONDS.convert(System.currentTimeMillis(), TimeUnit.MILLISECONDS) + TimeUnit.NANOSECONDS.convert(delay, dealyTimeUnit);
    }

    @Override
    public int compareTo(Delayed o) {
        // TODO Auto-generated method stub
        return 0;
    }

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

    public int getI() {
        return i;
    }

    public void setI(int i) {
        this.i = i;
    }
}

Upvotes: 1

Sanjeev Kumar
Sanjeev Kumar

Reputation: 660

As written in the java doc of DelayedQueue

Expiration occurs when an element's getDelay(TimeUnit.NANOSECONDS) method returns a value less than or equal to zero.

You have overridden the getDelay(TimeUnit.NANOSECONDS) method such that it is always returning a constant delay. You should change it so that delay decreases with time.

Something like

// startTime is some future time set while creating delay element.
public long getDelay(TimeUnit unit) {
        long diff = startTime - System.currentTimeMillis();
        return unit.convert(diff, TimeUnit.MILLISECONDS);
}

Upvotes: 3

user3374919
user3374919

Reputation: 1

Try to implment getDelay() in the below fashion. origin is the time in millisecond when you put the item in queue.

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

Upvotes: 0

Related Questions