DelayQueue 实现延时队列

写个文章记录一下

 

延迟队列不需要不停的扫描缓存、任务、轮训等,它能够实现在准确的时间点去执行任务

 

先创建一个DelayTask的对象,它要去实现Delayed接口 并且实现他的两个方法 getDelay()和 compareTo()

  • getDelay()   消息是否到期(是否可以被读取出来)判断的依据。当返回负数,说明消息已到期,此时消息就可以被读取出来了。
  • compareTo()  往DelayQueue里面塞入数据会执行这个方法,是数据应该排在哪个位置的判断依据。
  • 然后就是get()  set()  toString()方法啦!
  • TaskBase类 自己定义,例如:你执行任务时候所需要的数据! 这个类会被当做delayQueue 里面的Key ,增加任务,或者删除任务,用它来标识
public class DelayTask implements Delayed {
    /**
     * 任务ID
     */
    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 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;
    }

    @Override
    public String toString() {
        return "DelayTask{" +
                "data='" + data + '\'' +
                ", expire=" + expire +
                '}';
    }

 

然后创建一个控制类DelayQueueManager,用来操控DelayQueue还需要实现CommandLineRunner接口完成资源初始化

  • @Component 注解要加上
  • 实现CommandLineRunner接口后,在项目启动后会执行run方法
  • run方法创建一个线程去执行延时队列
@Component
public class DelayQueueManager implements CommandLineRunner {

    private final Logger logger = LoggerFactory.getLogger(DelayQueueManager.class);
    //保存 需要执行的信息
    private DelayQueue delayQueue = new DelayQueue<>();

    //这个是我的 业务类,注入进来,方便在下面调用
    @Autowired
    private TimedTask timedTask;

    /**
     * 加入到延时队列中
     * @param task
     */
    public void put(DelayTask task) {
        delayQueue.put(task);
    }

    /**
     * 删除延时任务
     * @param taskid
     * @return
     */
    public boolean remove(String taskid) {
       //xxxxxx 是指DelayTask类,这个类是作为Key的
        return delayQueue.remove(xxxxxx);
    }

    /**
     * 项目启动后开启一个线程 用来执行延时任务
     * @param args
     * @throws Exception
     */
    @Override
    public void run(String... args) throws Exception {
        Executors.newSingleThreadExecutor().execute(new Thread(this::excuteThread));
    }

    /**
     * 延时任务执行线程
     */
    private void excuteThread() {
        while (true) {
            try {
                /**
                 * 获取需要执行的 延时任务信息
                 */
                DelayTask task = delayQueue.take();
                //开始执行processTask方法
                processTask(task);
            } catch (InterruptedException e) {
                break;
            }
        }
    }

    /**
     * 执行延时任务
     * @param task
     */
    private void processTask(DelayTask task) {
       //你的业务逻辑 
    }


}

 

TaskBase类就不贴出来了,这就是一个普通类,自定义去吧!

要使用延时队列就直接@Autowired 把操作类注入进去吧

 

你可能感兴趣的:(java)