【问题标题】:How do i set up a DelayQueue's Delay我如何设置延迟队列的延迟
【发布时间】:2014-04-22 12:36:47
【问题描述】:

我刚刚开始使用 java 进行编码,我正在努力设置延迟队列,

我想拥有它,

DelayQueue queue = new DelayQueue();

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

我只是想学习所有的基础知识,我已经阅读了 API,但似乎无法掌握它。

提前致谢

【问题讨论】:

    标签: java queue delay timeunit


    【解决方案1】:

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

    • compareTo() 的实现不进行任何类转换,消除了抛出ClassCastException 的可能性
    • 在转换为 int 之前,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);
        }
    }
    

    JUnit 单元测试展示了使用TestDelay 类的示例:

    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的输出:

    【讨论】:

      【解决方案2】:

      DelayQueue 将元素保留在内部,直到某个延迟到期。元素必须实现接口java.util.concurrent.Delayed

      例如我创建了一个类DelayedTest 扩展延迟接口。这将实现 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

      【讨论】:

      • 因此,例如,如果我添加到延迟队列的元素是访问过的城市 E.G. “巴黎”和欧盟内部每个城市的延迟必须是 12 分钟,欧盟以外的每个城市必须是 6 分钟。我无法使用 queue.offer(The City, The Delay) 设置延迟?
      • @Pstie> 您可以根据需要设置deleyTimes,请注意,当元素的getDelay() 方法返回非正值时,该元素已过期。如需更多信息,请参阅thisthis
      • 为什么getDelay总是返回0?
      • @Paul 抱歉,打错了,已修复。
      【解决方案3】:
      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
                      + "]";
          }
      
      }
      

      【讨论】:

        【解决方案4】:

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

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

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

        【讨论】:

        • 但是我如何首先将延迟与对象关联起来?我的印象是我可以为每个对象设置不同的时间,它们都可以降到 0(然后更低),所以例如,如果我将整数 21 添加到延迟队列中,我可以将 21 设置为 16 的计时器分钟后才能再次使用。感谢您的快速回复。
        • 你可以在你的类中添加一个setDelay() 方法来手动设置一个静态延迟,然后返回而不是计算它。
        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2018-07-25
        • 2013-09-27
        • 1970-01-01
        • 1970-01-01
        • 2015-09-30
        • 2014-06-10
        • 1970-01-01
        相关资源
        最近更新 更多