温馨提示×

温馨提示×

您好,登录后才能下订单哦!

密码登录×
登录注册×
其他方式登录
点击 登录注册 即表示同意《亿速云用户服务条款》

springboot执行延时任务中DelayQueue怎么用

发布时间:2021-09-23 15:15:21 来源:亿速云 阅读:345 作者:小新 栏目:编程语言

这篇文章主要为大家展示了“springboot执行延时任务中DelayQueue怎么用”,内容简而易懂,条理清晰,希望能够帮助大家解决疑惑,下面让小编带领大家一起研究并学习一下“springboot执行延时任务中DelayQueue怎么用”这篇文章吧。

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

定义一个延时任务管理类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;@Componentpublic 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怎么用”这篇文章的所有内容,感谢各位的阅读!相信大家都有了一定的了解,希望分享的内容对大家有所帮助,如果还想学习更多知识,欢迎关注亿速云行业资讯频道!

向AI问一下细节

免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。

AI