• 欢迎访问搞代码网站,推荐使用最新版火狐浏览器和Chrome浏览器访问本网站!
  • 如果您觉得本站非常有看点,那么赶紧使用Ctrl+D 收藏搞代码吧

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

springboot 搞代码 4年前 (2022-01-05) 55次浏览 已收录 0个评论

DelayQueue是一个无界阻塞队列,只有在延迟期满时,才能从中提取元素。这篇文章主要介绍了springboot执行延时任务-DelayQueue的使用,需要的朋友可以参考下

DelayQueue简介

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

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

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

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

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

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

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

队列元素说明

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

 public interface Delayed extends Comparable { /** * 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 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 Thr<em style="color:transparent">来源[email protected]搞@^&代*@码)网</em>ead(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的使用详解的详细内容,更多请关注gaodaima搞代码网其它相关文章!


搞代码网(gaodaima.com)提供的所有资源部分来自互联网,如果有侵犯您的版权或其他权益,请说明详细缘由并提供版权或权益证明然后发送到邮箱[email protected],我们会在看到邮件的第一时间内为您处理,或直接联系QQ:872152909。本网站采用BY-NC-SA协议进行授权
转载请注明原文链接:springboot执行延时任务之DelayQueue的使用详解

喜欢 (0)
[搞代码]
分享 (0)
发表我的评论
取消评论

表情 贴图 加粗 删除线 居中 斜体 签到

Hi,您需要填写昵称和邮箱!

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址