DelayQueue简介

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

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

定义一个延时任务管理类DelayQueueManager,通过@Component注解加入到spring中管理,在需要使用的地方通过@Autowire注入

import com.alibaba.fastjson.JSON;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.CommandLineRunner;
import org.springframework.stereotype.Component; import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.concurrent.DelayQueue;
import java.util.concurrent.Executors; @Component
public class DelayQueueManager implements CommandLineRunner {
private final Logger logger = LoggerFactory.getLogger(DelayQueueManager.class);
private DelayQueue<DelayTask> delayQueue = new DelayQueue<>(); /**
* 加入到延时队列中
* @param task
*/
public void put(DelayTask task) {
logger.info("加入延时任务:{}", task);
delayQueue.put(task);
} /**
* 取消延时任务
* @param task
* @return
*/
public boolean remove(DelayTask task) {
logger.info("取消延时任务:{}", task);
return delayQueue.remove(task);
} /**
* 取消延时任务
* @param taskid
* @return
*/
public boolean remove(String taskid) {
return remove(new DelayTask(new TaskBase(taskid), 0));
} @Override
public void run(String... args) throws Exception {
logger.info("初始化延时队列");
Executors.newSingleThreadExecutor().execute(new Thread(this::excuteThread));
} /**
* 延时任务执行线程
*/
private void excuteThread() {
while (true) {
try {
DelayTask task = delayQueue.take();
processTask(task);
} catch (InterruptedException e) {
break;
}
}
} /**
* 内部执行延时任务
* @param task
*/
private void processTask(DelayTask task) {
logger.info("执行延时任务:{}", task);
//根据task中的data自定义数据来处理相关逻辑,例 if (task.getData() instanceof XXX) {}
}
}

DelayQueueManager实现了CommandLineRunner接口,在springboot启动完成后就会自动调用run方法。

												

springboot执行延时任务-DelayQueue的使用的更多相关文章

  1. SpringBoot执行定时任务@Scheduled

    SpringBoot执行定时任务@Scheduled 在做项目时,需要一个定时任务来接收数据存入数据库,后端再写一个接口来提供该该数据的最新的那一条. 数据保持最新:设计字段sign的值(0,1)来设 ...

  2. ios想要取消执行延时调用的方法

    想要取消执行延时调用的方法: [[self class] cancelPreviousPerformRequestsWithTarget:self selector:@selector(hideDia ...

  3. SpringBoot执行原理

    目录 [Toc] 一.执行原理: 每个Spring Boot项目都有一个主程序启动类,在主程序启动类中有一个启动项目的main()方法, 在该方法中通过执行SpringApplication.run( ...

  4. springboot执行流程

    构造方法初始化,创建一个新的实例,这个应用程序的上下文要从指定的来源加载bean public SpringApplication(ResourceLoaderresourceLoader,Class ...

  5. SpringBoot执行定时任务

    1.在启动类中加入@EnableScheduling来开启定时任务. package com.example.demo; import org.springframework.boot.SpringA ...

  6. 分布式 redis 延时任务 基于 springboot 示例

    Lilishop 技术栈 官方公众号 & 开源不易,如有帮助请点Star 介绍 官网:https://pickmall.cn Lilishop 是一款Java开发,基于SpringBoot研发 ...

  7. iOS:延时执行的三种方式

    延时执行的三种方式:performSelectorXXX方法.GCD中延时函数.创建定时器   第一种方式:NSObject分类当中的方法,延迟一段时间调用某一个方法 @interface NSObj ...

  8. java并发编程工具类JUC第三篇:DelayQueue延时队列

    DelayQueue 是BlockingQueue接口的实现类,它根据"延时时间"来确定队列内的元素的处理优先级(即根据队列元素的"延时时间"进行排序).另一层 ...

  9. 延时任务-基于redis zset的完整实现

    所谓的延时任务给大家举个例子:你买了一张火车票,必须在30分钟之内付款,否则该订单被自动取消.订单30分钟不付款自动取消,这个任务就是一个延时任务. 我之前已经写过2篇关于延时任务的文章: <完 ...

随机推荐

  1. php 全文搜索搜索-讯搜使用

    相信很多朋友遇到过,需要全文搜索的场景,百度了一圈发现了一个xunsearch 首先本地采集了1万篇文章,发现效率还可以. 使用上也很简单,直接上代码 //接收关键词 $xs = new XS('xp ...

  2. 8.3 NOIP CE反思

    lsc考完以后就CE了,然后滚回去吃*去了! 这次考试都比的一批,整个先是打了暴力然后对拍发现桶有可能炸内存,然后就打了一个hash-map然后......T1 T3全使用了它,结果: 没什么可说的了 ...

  3. Electron 菜单切换主题与css替换 ts编写

    ////目标css<link rel="stylesheet" id="theme_css" href="路径"> ////ts ...

  4. Mybatis批量事务处理

    /** * 批量提交数据 * @param sqlSessionFactory * @param mybatisSQLId SQL语句在Mapper XML文件中的ID * @param commit ...

  5. 基于.NetStandard的简易EventBus实现-基础实现

    一.问题背景 最近离职来到了一家新的公司,原先是在乙方工作,这回到了甲方,在这一个月中,发现目前的业务很大一部分是靠轮询实现的,例如:通过轮询判断数据处于B状态了,则轮询到数据后执行某种动作,这个其实 ...

  6. 函数的prototype

    1.函数的prototype属性 每一个函数都有一个prototype属性,默认指向object空对象(原型对象),每一个原型对象都有一个constructor属性,指向函数对象 2.给原型对象添加属 ...

  7. scrapy_redis分布式爬虫

    文章来源:https://github.com/rmax/scrapy-redis Scrapy-Redis Documentation: https://scrapy-redis.readthedo ...

  8. Vue packages version mismatch版本问题的解决

    今天下载了一个vue项目,npm run dev 时发现报错,错误信息入下: error in .src/components/mobile/SeniorDetail.vue Module build ...

  9. goland_beego框架学习--api实现

    goland_beego框架学习--api实现 完成一项api实现的流程 (1)beego框架的router层里面注册路由 正则路由 为了用户更加方便的路由设置,beego 参考了 sinatra 的 ...

  10. PostGIS mysql_fdw使用(Linux)

    ##前文讲了mysql_fdw的安装,此文主要讲mysql_fdw的配置以及使用 ##附上前文链接:https://www.cnblogs.com/giser-s/p/11208803.html 背景 ...