Java中的DelayQueue

时间:2020-01-09 10:35:11  来源:igfitidea点击:

Java中的DelayQueue是BlockingQueue接口的实现,并且是java.util.concurrent包的一部分。 Java中的DelayQueue是一个无界队列,它与ArrayBlockingQueue是有界队列不同。

延迟接口

Java DelayQueue只能存储类型为Delayed的元素。 Java中有一个接口Delayed,它定义了这些元素的类型。

延迟接口用于定义在给定延迟后应作用的对象的类型。

public interface Delayed extends Comparable<Delayed> {
    long getDelay(TimeUnit unit);
}

getDelay(TimeUnit unit)方法以给定的时间单位返回与此对象关联的剩余延迟。
由于Delayed接口还扩展了Comparable接口,因此此接口的实现必须定义一个compareTo()方法,该方法提供与其getDelay方法一致的顺序。

DelayQueue过期的元素

从Java中的DelayQueue中,只能在元素的延迟到期后才能使用它。元素是从队列的开头获取的,这意味着队列的开头是该Delayed元素,其延迟在过去最远时过期。

当元素的getDelay(TimeUnit.NANOSECONDS)方法返回的值小于或者等于零时,队列中的元素就会过期。

诸如take()之类的阻塞方法将等待,直到该队列上具有过期延迟的元素可用。

Java中的DelayQueue的功能

  • DelayQueue存储类型为Delayed的元素。接口延迟定义了这些延迟元素的类型。
  • 只有在延迟到期后才能从DelayQueue中获取元素。
  • DelayQueue是线程安全的实现。
  • Java中的DelayQueue不允许添加null元素。

Java DelayQueue构造函数

  • DelayQueue()–创建一个最初为空的新DelayQueue。
  • DelayQueue(Collection <?扩展E> c)-创建一个DelayQueue,最初包含给定的Delayed实例集合的元素。

DelayQueue Java示例

这是使用DelayQueue的生产者-消费者示例。由于DelayQueue存储类型为Delayed的元素,因此我们也需要实现Delayed接口。

private long expiryTime;
  DelayQElement(String queueElement, long delay){
    this.queueElement = queueElement;
    // Expirytime is current time + delay
    this.expiryTime = System.currentTimeMillis() + delay;
    System.out.println("Putting queueElement "  + queueElement + " expiry " + this.expiryTime);
  }
 
  @Override
  public long getDelay(TimeUnit unit) {
    long diff = expiryTime - System.currentTimeMillis();
    return unit.convert(diff, TimeUnit.MILLISECONDS);
  }
 
  @Override
  public int compareTo(Delayed o) {
  if(this.getDelay(TimeUnit.MILLISECONDS) < o.getDelay(TimeUnit.MILLISECONDS)){ 
    return -1; 
  } 
  if(this.getDelay(TimeUnit.MILLISECONDS) > o.getDelay(TimeUnit.MILLISECONDS)){
    return 1;
  }
  return 0;     
  }
  public String toString(){
    return queueElement + " Expiry Time= " + expiryTime;
  } 
}

使用DelayQueue的生产者-消费者

public class DQDemo {
  public static void main(String[] args) {
    // delay of 3 seconds
    final long delay = 3000;
    BlockingQueue<DelayQElement> delayQ = new DelayQueue<DelayQElement>();
    // Producer thread
    new Thread(()->{
      for(int i = 0; i < 5; i++){
        try {
          delayQ.put(new DelayQElement("Element"+i, delay));
          Thread.sleep(50);
        } catch (InterruptedException e) {
          // TODO Auto-generated catch block
          e.printStackTrace();
        }
      }
    }).start();
        
    // Consumer thread
    new Thread(()->{
      for(int i = 0; i < 5; i++){
        try {
          System.out.println(" Consumer got - " + delayQ.take().toString());
          Thread.sleep(100);
        } catch (InterruptedException e) {
          // TODO Auto-generated catch block
          e.printStackTrace();
        }
      }
    }).start();
  }
}

输出:

Putting queueElement Element0expiry 1541830388935
Putting queueElement Element1expiry 1541830388998
Putting queueElement Element2expiry 1541830389060
Putting queueElement Element3expiry 1541830389123
Putting queueElement Element4expiry 1541830389185
 Consumer got - Element0 Expiry Time= 1541830388935
 Consumer got - Element1 Expiry Time= 1541830388998
 Consumer got - Element2 Expiry Time= 1541830389060
 Consumer got - Element3 Expiry Time= 1541830389123
 Consumer got - Element4 Expiry Time= 1541830389185

如我们所见,元素在元素过期后从队列中取出。

DelayQueue类方法

这是Java中DelayQueue类的一些方法的列表。

  • add(E e)–将指定的元素插入此延迟队列。
  • clear()–以原子方式从此延迟队列中删除所有元素。
  • offer(E e)–将指定的元素插入此延迟队列。
  • peek()–检索但不删除此队列的头,如果此队列为空,则返回null。
  • poll()–检索并删除此队列的头部,如果此队列没有延迟过期的元素,则返回null。
  • poll(long timeout,TimeUnit unit)–检索并删除此队列的头部,如有必要,请等待直到该队列上具有过期延迟的元素可用,或者指定的等待时间到期为止。
  • put(E e)–将指定的元素插入此延迟队列。
  • remove(Object o)–从该队列中移除指定元素的单个实例(如果存在),无论该元素是否已过期。
  • take()–检索并删除此队列的头部,如有必要,请等待直到延迟过期的元素在此队列上可用。