Java 延迟队列的常用的实现方式
作者:废物大师兄 发布时间:2022-06-30 13:57:00
标签:Java,延迟队列
延迟队列的使用场景还比较多,例如:
1、超时未收到支付回调,主动查询支付状态;
2、规定时间内,订单未支付,自动取消;
。。。
总之,但凡需要在未来的某个确定的时间点执行检查的场景中都可以用延迟队列。
常见的手段主要有:定时任务扫描、RocketMQ延迟队列、Java自动的延迟队列、监听Redis Key过期等等
1. DelayQueue
首先,定义一个延迟任务
package com.cjs.example;
import lombok.Data;
import java.util.concurrent.Delayed;
import java.util.concurrent.TimeUnit;
/**
* @author ChengJianSheng
* @since 2021/3/18
*/
@Data
public class DelayTask implements Delayed {
private Long orderId;
private long expireTime;
public DelayTask(Long orderId, long expireTime) {
this.orderId = orderId;
this.expireTime = expireTime;
}
@Override
public long getDelay(TimeUnit unit) {
return expireTime - System.currentTimeMillis();
}
@Override
public int compareTo(Delayed o) {
return (int) (getDelay(TimeUnit.MILLISECONDS) - o.getDelay(TimeUnit.MILLISECONDS));
}
}
然后,定义一个管理类
package com.cjs.example;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.CommandLineRunner;
import org.springframework.stereotype.Component;
import java.util.concurrent.DelayQueue;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
/**
* @author ChengJianSheng
* @since 2021/3/19
*/
@Slf4j
@Component
public class DelayQueueManager implements CommandLineRunner {
private DelayQueue<DelayTask> queue = new DelayQueue<>();
@Autowired
private ParkOrderQueryHandler handler;
@Override
public void run(String... strings) throws Exception {
ExecutorService executorService = Executors.newSingleThreadExecutor();
executorService.execute(new Runnable() {
@Override
public void run() {
while (true) {
try {
DelayTask task = queue.take();
handler.handle(task);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
});
}
public void put(DelayTask task) {
queue.put(task);
}
}
插入任务
@Slf4j
@Service
public class PayServiceImpl implements PayService {
@Autowired
private DelayQueueManager delayQueueManager;
@Override
public void pay() {
delayQueueManager.put(new DelayTask(1, 15));
delayQueueManager.put(new DelayTask(2, 30));
delayQueueManager.put(new DelayTask(3, 60));
}
}
2. Redis Key过期回调
修改redis.conf文件
# bind 127.0.0.1 -::1
protected-mode no
notify-keyspace-events Ex
[root@localhost redis-6.2.1]$ src/redis-server redis.conf
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.4.4</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.example</groupId>
<artifactId>demo0401</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>demo0401</name>
<description>Demo project for Spring Boot</description>
<properties>
<java.version>1.8</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
RedisConfig.java
package com.example.config;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.listener.RedisMessageListenerContainer;
/**
* @author ChengJianSheng
* @since 2021/4/2
*/
@Configuration
public class RedisConfig {
@Bean
public RedisMessageListenerContainer container(RedisConnectionFactory connectionFactory) {
RedisMessageListenerContainer container = new RedisMessageListenerContainer();
container.setConnectionFactory(connectionFactory);
return container;
}
}
创建一个监听类
package com.example.listener;
import org.springframework.data.redis.connection.Message;
import org.springframework.data.redis.listener.KeyExpirationEventMessageListener;
import org.springframework.data.redis.listener.RedisMessageListenerContainer;
import org.springframework.stereotype.Component;
/**
* @author ChengJianSheng
* @since 2021/4/2
*/
@Component
public class MyRedisKeyExpirationListener extends KeyExpirationEventMessageListener {
public MyRedisKeyExpirationListener(RedisMessageListenerContainer listenerContainer) {
super(listenerContainer);
}
@Override
public void onMessage(Message message, byte[] pattern) {
String expiredKey = message.toString();
System.out.println("监听到Key: " + expiredKey + " 已过期");
}
}
3. RocketMQ
官方文档:https://help.aliyun.com/document_detail/29549.htm
来源:https://www.cnblogs.com/cjsblog/p/14612169.html


猜你喜欢
- 下面是我做C#第一个项目的过程:1.首先打开VS,这里我用的是VS2022预览版,鼠标双击打开VS;图一2.打开VS后会出现下面的页面,鼠标
- 前言:本文主要讲解以c语言编写猜数字游戏,目的是介绍C语言中的循环和分支的具体用法。一:猜数字游戏基本介绍&对程序预期.猜数字游戏,
- Flutter自适应瀑布流前言:在电商app经常会看到首页商品推荐的瀑布流,或者类似短视频app首页也是瀑布流,这些都是需要自适应的,才能给
- 业务场景通常微服务对于用户认证信息解析有两种方案在 gateway 就解析用户的 token 然后路由的时候把 userId 等相关信息添加
- 前言标签(Label)控件是最常用的控件,在任何Windows应用程序中都可以中都可以看到标签控件。标签控件用于显示用户不能编辑的文件或图像
- spring-mybatis获取mapper方式汇总项目背景:pojo下面有一个user实体类Dao包下面写了usermapper.xml
- 异常的英文单词是exception,字面翻译就是“意外、例外”的意思,也就是非正常情况。事实上,异常本质上是程序上的错误,包括程序逻辑错误和
- 前言一个简单的单机小游戏:flypybird ,用来巩固java基础。涉及主要知识点:JFrame 、 JPanel 、 继承、 键盘/鼠标
- 目录背景Shutdown Hook 介绍关闭钩子被调用场景注意事项实践Shutdown Hook 在 Spring 中的运用背景如果想在 J
- 前言基于安卓平台的连续滚动图像组件ContinuousScrollableImageView(https://github.com/Cutt
- 现象在日志配置文件 logback-spring.xml 中,无论怎么修改级别,mybatis 的 sql 日志都会打印出来。原因在 app
- <FrameLayout &
- 写在前面项目中直接引用或者直接编译源码得到的ijkplayer在播放mkv文件时出现(-10000)的错误,去项目github查看了才知道,
- 本文实例为大家分享了Java实现图形界面计算器的具体代码,供大家参考,具体内容如下 代码:import javax.swing.*
- Android开发sdk过程中,很有可能在sdk内部引
- 本文实例讲述了C#调用存储过程的方法。分享给大家供大家参考,具体如下:CREATE PROCEDURE [dbo].[GetNameById
- 快捷键辅助类 class HotKey { /// <summary> /// 如果函数执行成功,返回值不为0。 /// 如果函
- 最近由于编程的需要,对 C# 的类型转换做了一些研究,其内容涉及 C# 的装箱/拆箱/别名、数值类型间相互转换、字符的 ASCII 码和 U
- Java * 分析及理解代理设计模式定义:为其他对象提供一种代理以控制对这个对象的访问。 * 使用java * 机制以巧妙的方式实现了
- 干java 开发这么多年, 之前一直没留意java 进程还区分守护进程和用户进程。守护进程这个概念最早还是在linux系统中接触的,直到近期