Reputation: 2445
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
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
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
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