如何设置 DelayQueue 的延迟时间?

4
我是一名初学Java编程的人,目前在设置DelayQueue方面遇到了困难。
我想要实现以下功能:
DelayQueue queue = new DelayQueue();

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

我只是在试图学习所有的基础知识,读过API文档,但似乎无法理解。

提前感谢您。

4个回答

8

Delayed的这个实现很好,因为:

  • compareTo()的实现不进行任何类转换,消除了抛出ClassCastException的可能性。
  • compareTo()的实现在进行强制类型转换之前使用Math.minMath.max函数,以正确防止溢出错误。
  • getDelay()的实现正确地转换了单位,并实际返回剩余时间。

TestDelay类实现了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);
    }
}

这是一个使用TestDelay类的JUnit单元测试示例:

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);
        }
    }
}
DelayQueueTest的输出结果如下:

unit test output


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
                + "]";
    }

}

1

您的“自定义延迟”类必须返回Delayed接口中指定的getDelay(TimeUnit timeUnit)方法中的延迟。

例如:

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

请注意,您还需要为compareTo()提供实现。

但是我如何将延迟与对象关联起来呢?我原本以为我可以为每个对象设置不同的时间,它们都会倒计时到0(然后再往下),所以例如如果我将整数21添加到DelayQueue中,我能否将21设置为在16分钟后才能再次使用。感谢您的快速回复。 - Pstie
你可以在你的类中添加一个 setDelay() 方法来手动设置静态延迟,并返回它而不是计算它。 - Kayaman

0

DelayQueue 会在一定延迟时间后才释放其内部元素。这些元素必须实现接口 java.util.concurrent.Delayed

例如,我创建了一个类 DelayedTest,它继承了 Delayed 接口。该类需要实现 compareTo 方法和 getDelay() 方法。

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); 
    }

}

结果:

5
10
15

例如,如果我要添加到DelayQueue的元素i是已访问城市,比如“巴黎”,并且欧盟内每个城市的延迟时间为12分钟,欧盟外每个城市的延迟时间为6分钟。我不能使用queue.offer(城市延迟时间)来设置延迟吗? - Pstie
1
@Pstie> 您可以根据需要设置deleyTime,但请注意,当元素的getDelay()方法返回非正值时,该元素将过期。有关更多信息,请参见此处此处 - Mohsen Kamrani
4
为什么 getDelay 总是返回 0? - Paul
@Paul 抱歉,是打错了,已经修正了。 - Mohsen Kamrani

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接