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. python机器学习——随机梯度下降

    上一篇我们实现了使用梯度下降法的自适应线性神经元,这个方法会使用所有的训练样本来对权重向量进行更新,也可以称之为批量梯度下降(batch gradient descent).假设现在我们数据集中拥有大 ...

  2. volatile相关内容

    volatile是jvm提供的轻量级的同步机制 保证可见性(一个线程的修改对其它线程是可见的) 不保证原子性 禁止指令重排序 什么是指令重排? 计算机在执行程序时,为了提高性能,编译器和处理器会对指令 ...

  3. 解决WordPress不能发邮件,WordPress 无法发送邮件

    解决WordPress不能发邮件,WordPress 无法发送邮件,不得不说WordPress这个问题真的很烦人,研究了一下午发现不能发邮件的问题无非以下几种! 1.系统本身问题,这个直接装个插件即可 ...

  4. visible:hidden和dispaly:none的区别

    display:none和visible:hidden都能把网页上某个元素隐藏起来,但两者有区别: display:none ---不为被隐藏的对象保留其物理空间,即该对象在页面上彻底消失,通俗来说就 ...

  5. 用大写字母输入 Linux 命令,实现以 sudo 用户权限运行

    我们知道,一些 Linux 命令是要通过 sudo 权限才能运行的,这需要我们每次使用这些命令时在前面加一个 sudo ,十分繁琐.今天给大家介绍一个好用的工具 SUDO ,它只需要我们用大写字母键入 ...

  6. nyoj 50-爱摘苹果的小明 (比较)

    50-爱摘苹果的小明 内存限制:64MB 时间限制:1000ms Special Judge: No accepted:10 submit:15 题目描述: 小明家的院子里有一棵苹果树,每到秋天树上就 ...

  7. Redis单节点数据同步到Redis集群

    一:Redis集群环境准备 1:需要先安装好Redis集群环境并配置好集群 192.168.0.113 7001-7003 192.168.0.162 7004-7006 2:检查redis集群 [r ...

  8. 【Java】面向对象之继承

    多个类中存在相同属性和行为时,将这些内容抽取到单独一个类中,那么多个类无需再定义这些属性和行为,只要继承那一个类即可.其中如图中所示,食草动物.食肉动物.兔子.羊.狮子.豹都可以称为子类,动物类称为父 ...

  9. bash:echo

    echo 'xxxx'自带换行 echo -n ‘xxxxxx’ 取消换行 echo -e "xxxxxxxxxxxx"允许转义字符(两种引号对转以字符效果相同,影响$变量) 转义 ...

  10. [springboot 开发单体web shop] 8. 商品详情&评价展示

    上文回顾 上节 我们实现了根据搜索关键词查询商品列表和根据商品分类查询,并且使用到了mybatis-pagehelper插件,讲解了如何使用插件来帮助我们快速实现分页数据查询.本文我们将继续开发商品详 ...