4

I'm just starting out coding in java i'm in struggling with setting up a DelayQueue,

I wanted to have it so,

DelayQueue queue = new DelayQueue();

If (counter > 0){
queue.offer(Integer, *A custom delay*)
} Else {
queue.offer(Integer, *A different custom delay*)
}

I'm just trying to learn all the basics and ive read over the API and cant seem to grasp it.

Thanks in advance

Pstie
  • 85
  • 1
  • 2
  • 4

4 Answers4

8

this implementation of Delayed is good because:

  • implementation of compareTo() does not do any class casting, eliminatig the possibility of throwing a ClassCastException
  • implementation of compareTo() uses Math.min and Math.max functions before casting to int in order to properly prevent overflow errors
  • implementation of getDelay() properly converts the units and actually returns the time remaining

TestDelay class implements Delayed:

import org.jetbrains.annotations.NotNull;

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

public class TestDelay implements Delayed
{
    public final Long delayMillis;
    public final Long expireTimeMillis;

    public TestDelay(Long delayMillis)
    {
        this.delayMillis = delayMillis;
        this.expireTimeMillis = System.currentTimeMillis()+delayMillis;
    }

    @Override
    public final int compareTo(@NotNull Delayed o)
    {
        long diffMillis = getDelay(TimeUnit.MILLISECONDS)-o.getDelay(TimeUnit.MILLISECONDS);
        diffMillis = Math.min(diffMillis,1);
        diffMillis = Math.max(diffMillis,-1);
        return (int) diffMillis;
    }

    @Override
    public final long getDelay(@NotNull TimeUnit unit)
    {
        long delayMillis = expireTimeMillis-System.currentTimeMillis();
        return unit.convert(delayMillis,TimeUnit.MILLISECONDS);
    }
}

JUnit unit test showing an example of using the TestDelay class:

import org.junit.Test;

import java.util.concurrent.DelayQueue;

public class DelayQueueTest
{
    @Test
    public final void generalTest() throws InterruptedException
    {
        DelayQueue<TestDelay> q = new DelayQueue<>();
        q.put(new TestDelay(500L));
        q.put(new TestDelay(2000L));
        q.put(new TestDelay(1000L));
        q.put(new TestDelay(10L));
        q.put(new TestDelay(3000L));
        while (!q.isEmpty())
        {
            System.out.println(q.take().delayMillis);
        }
    }
}

output of DelayQueueTest:

unit test output

Eric
  • 16,397
  • 8
  • 68
  • 76
7
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.DelayQueue;
import java.util.concurrent.Delayed;
import java.util.concurrent.TimeUnit;

public class DelayQueueExample {

    public static void main(String[] args) {

        BlockingQueue<DelayedElement> blockingQueue = new DelayQueue<DelayedElement>();

        try {
            blockingQueue
                    .put(new DelayedElement(4000, "Message with delay 4s"));
            blockingQueue
                    .put(new DelayedElement(2000, "Message with delay 2s"));
            blockingQueue
                    .put(new DelayedElement(9000, "Message with delay 9s"));
        } catch (InterruptedException ie) {
        }

        while (!blockingQueue.isEmpty()) {
            try {
                System.out.println(">>" + blockingQueue.take());
            } catch (InterruptedException ie) {
            }

        }

    }
}

class DelayedElement implements Delayed {

    private long duration = 0;
    private String message;

    public DelayedElement(long duration, String name) {
        this.duration = System.currentTimeMillis() + duration;
        this.message = name;
    }

    @Override
    public int compareTo(Delayed o) {
        return (int) (this.duration - ((DelayedElement) o).getDuration());
    }

    @Override
    /*
     * Expiration occurs when an element's getDelay(TimeUnit unit) method
     * returns a value less than or equal to zero.
     */
    public long getDelay(TimeUnit unit) {
        long diff = duration - System.currentTimeMillis();
        return unit.convert(diff, TimeUnit.MILLISECONDS);
    }

    public long getDuration() {
        return duration;
    }

    public void setDuration(long duration) {
        this.duration = duration;
    }

    public String getMessage() {
        return message;
    }

    public void setMessage(String message) {
        this.message = message;
    }

    @Override
    public String toString() {
        return "DelayedElement [duration=" + duration + ", message=" + message
                + "]";
    }

}
leventov
  • 14,760
  • 11
  • 69
  • 98
Sandeep Bhardwaj
  • 1,310
  • 1
  • 18
  • 24
1

Your "custom delay" classes must return the delay from the getDelay(TimeUnit timeUnit) method specified in the Delayed interface. E.g.

public class MyClass implements Delayed {
    public long getDelay(TimeUnit timeUnit) {
        long delay = calculateDelaySomehow();
        return delay;
    }
}

Note that you also need to provide an implementation for compareTo().

Kayaman
  • 72,141
  • 5
  • 83
  • 121
  • But how do i associate a delay with the object in the first place? i was under the impression that i could set every object with a different time and they would all could down to 0 (and then below) so for example if i added the integer 21 to the DelayQueue can i set 21 to have a timer of 16 minutes before it is able to be used again. Thanks for the quick reply. – Pstie Apr 22 '14 at 12:50
  • You could add a `setDelay()` method in your class for manually setting a static delay, and returning that instead of calculating it. – Kayaman Apr 22 '14 at 13:04
0

The DelayQueue keeps the elements internally until a certain delay has expired. The elements must implement the interface java.util.concurrent.Delayed.

For example I have created a class DelayedTest extending Delayed interface. This will implement compareTo and getDelay() method

public class A{
    public static void main(String... args){
        DelayQueue  dq=new DelayQueue();
        DeleyedTest ob1=new DeleyedTest(10);
        DeleyedTest ob2=new DeleyedTest(5);
        DeleyedTest ob3=new DeleyedTest(15);

        dq.offer(ob1);
        dq.offer(ob2);
        dq.offer(ob3);

        Iterator itr=dq.iterator();
        while(itr.hasNext()){
            DeleyedTest dt=(DeleyedTest)itr.next();
            System.out.println(dt.deleyTime);
        }
    }
}
class DeleyedTest implements Delayed{
    public long deleyTime=0;
    DeleyedTest(long deleyTime){
        this.deleyTime=deleyTime;
    }

    @Override
    public int compareTo(Delayed ob) {
        if(this.deleyTime<((DeleyedTest)ob).deleyTime){
            return -1;
        }else if(this.deleyTime>((DeleyedTest)ob).deleyTime){
            return 1;
        }
        return 0;
    }
    @Override
    public long getDelay(TimeUnit unit) {
        return unit.convert(deleyTime-System.currentTimeMillis(),TimeUnit.NANOSECONDS); 
    }

}

Result:

5
10
15
Mohsen Kamrani
  • 7,177
  • 5
  • 42
  • 66
  • So for example if the element i was adding to the DelayQueue was cities visited E.G. "Paris" and the delay for every city inside the EU has to be 12 minutes and every city outside the EU has to be 6 minutes. i cannot set the delay with queue.offer(*The City*, *The Delay*) ? – Pstie Apr 22 '14 at 13:00
  • 1
    @Pstie> You can set the `deleyTime`s as you wish just please note that an element is expired when its `getDelay()` method returns a non-positive value. For more information please see [this](http://docs.oracle.com/javase/7/docs/api/java/util/concurrent/DelayQueue.html) and [this](http://www.javadocexamples.com/java_source/de/pxlab/pxl/display/TrackingTarget.java.html). – Mohsen Kamrani Apr 22 '14 at 13:05
  • 4
    Why does `getDelay` always return 0? – Paul Jan 27 '16 at 19:59
  • @Paul Sorry, it was a typo, fixed it. – Mohsen Kamrani Jan 02 '19 at 02:05