当前位置 主页 > 服务器问题 > Linux/apache问题 >

    springboot执行延时任务之DelayQueue的使用详解

    栏目:Linux/apache问题 时间:2019-12-13 22:18

    DelayQueue简介

    DelayQueue是一个无界阻塞队列,只有在延迟期满时,才能从中提取元素。
    队列的头部,是延迟期满后保存时间最长的delay元素。

    在很多场景我们需要用到延时任务,比如给客户异步转账操作超时后发通知告知用户,还有客户下单后多长时间内没支付则取消订单等等,这些都可以使用延时任务来实现。

    jdk中DelayQueue可以实现上述需求,顾名思义DelayQueue就是延时队列。

    DelayQueue提供了在指定时间才能获取队列元素的功能,队列头元素是最接近过期的元素。

    没有过期元素的话,使用poll()方法会返回null值,超时判定是通过getDelay(TimeUnit.NANOSECONDS)方法的返回值小于等于0来判断。

    延时队列不能存放空元素。

    一般使用take()方法阻塞等待,有过期元素时继续。

    队列元素说明

    DelayQueue<E extends Delayed>的队列元素需要实现Delayed接口,该接口类定义如下:

    public interface Delayed extends Comparable<Delayed> {
    
     /**
      * Returns the remaining delay associated with this object, in the
      * given time unit.
      *
      * @param unit the time unit
      * @return the remaining delay; zero or negative values indicate
      * that the delay has already elapsed
      */
     long getDelay(TimeUnit unit);
    }

    所以DelayQueue的元素需要实现getDelay方法和Comparable接口的compareTo方法,getDelay方法来判定元素是否过期,compareTo方法来确定先后顺序。

    springboot中实例运用

    DelayTask就是队列中的元素

    import java.util.Date;
    import java.util.concurrent.Delayed;
    import java.util.concurrent.TimeUnit;
    public class DelayTask implements Delayed {
     final private TaskBase data;
     final private long expire;
     /**
      * 构造延时任务
      * @param data  业务数据
      * @param expire 任务延时时间(ms)
      */
     public DelayTask(TaskBase data, long expire) {
      super();
      this.data = data;
      this.expire = expire + System.currentTimeMillis();
     }
     public TaskBase getData() {
      return data;
     }
     public long getExpire() {
      return expire;
     }
     @Override
     public boolean equals(Object obj) {
      if (obj instanceof DelayTask) {
       return this.data.getIdentifier().equals(((DelayTask) obj).getData().getIdentifier());
      }
      return false;
     }
     @Override
     public String toString() {
      return "{" + "data:" + data.toString() + "," + "expire:" + new Date(expire) + "}";
     }
     @Override
     public long getDelay(TimeUnit unit) {
      return unit.convert(this.expire - System.currentTimeMillis(), unit);
     }
     @Override
     public int compareTo(Delayed o) {
      long delta = getDelay(TimeUnit.NANOSECONDS) - o.getDelay(TimeUnit.NANOSECONDS);
      return (int) delta;
     }
    }

    TaskBase类是用户自定义的业务数据基类,其中有一个identifier字段来标识任务的id,方便进行索引

    import com.alibaba.fastjson.JSON;
    public class TaskBase {
     private String identifier;
     public TaskBase(String identifier) {
      this.identifier = identifier;
     }
     public String getIdentifier() {
      return identifier;
     }
     public void setIdentifier(String identifier) {
      this.identifier = identifier;
     }
     @Override
     public String toString() {
      return JSON.toJSONString(this);
     }
    }