在SpringBoot中使用redis中的zset实现延迟任务

为什么使用zset实现延迟任务

ZSET(有序集合)适合实现延迟任务的原因主要有以下几点:

  1. 排序特性ZSET根据分数(score)自动排序,这使得我们可以将任务的执行时间作为分数,从而能够轻松地获取到即将执行的任务。
  2. 范围查询ZSET支持范围查询,我们可以查询分数在某个区间内的所有元素,这对于获取所有已到期的任务非常方便。
  3. 高效性ZSET的操作通常都是高效的,比如添加、删除和范围查询等操作的时间复杂度通常为O(log(N)),这使得它适合用于需要频繁操作的任务队列。
  4. 原子操作ZSET提供了原子操作,比如添加元素时如果元素已存在则会更新其分数,这有助于避免在并发环境中出现数据一致性问题。
  5. 灵活性ZSET允许同一个集合中存在多个相同分数的元素,这使得我们可以存储多个同一时间到期的任务。

实现步骤

1、添加redis依赖

xml 复制代码
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>

2、配置redis

yaml 复制代码
spring.redis.host=localhost
spring.redis.port=6379

3、创建ZSET操作服务

创建一个服务类来封装对ZSET的操作:

java 复制代码
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.ZSetOperations;
import org.springframework.stereotype.Service;
import java.util.Set;
@Service
public class DelayTaskService {
    // 定义一个常量作为延迟任务队列的键
    private static final String DELAY_TASK_KEY = "delayTaskQueue";
    // 注入RedisTemplate用于操作Redis
    private final RedisTemplate<String, String> redisTemplate;
    // 通过构造函数注入RedisTemplate
    @Autowired
    public DelayTaskService(RedisTemplate<String, String> redisTemplate) {
        this.redisTemplate = redisTemplate;
    }
    /**
     * 添加一个延迟任务
     * @param taskId 任务ID
     * @param delayMillis 延迟执行的毫秒数
     */
    public void addTask(String taskId, long delayMillis) {
        // 计算任务的执行时间(当前时间 + 延迟时间)
        long executeTime = System.currentTimeMillis() + delayMillis;
        // 将任务添加到ZSET中,分数为执行时间
        redisTemplate.opsForZSet().add(DELAY_TASK_KEY, taskId, executeTime);
    }
    /**
     * 处理到期的任务
     */
    public void processTasks() {
        // 获取当前时间
        long now = System.currentTimeMillis();
        // 查询ZSET中小于或等于当前时间的所有任务
        Set<String> tasks = redisTemplate.opsForZSet().rangeByScore(DELAY_TASK_KEY, 0, now);
        // 如果有任务,则进行处理
        if (tasks != null && !tasks.isEmpty()) {
            for (String taskId : tasks) {
                // 从ZSET中移除任务,如果移除成功(任务存在),则处理任务
                if (redisTemplate.opsForZSet().remove(DELAY_TASK_KEY, taskId) > 0) {
                    handleTask(taskId);
                }
            }
        }
    }
    /**
     * 处理具体的任务
     * @param taskId 任务ID
     */
    private void handleTask(String taskId) {
        // 这里实现任务处理的逻辑
        System.out.println("处理任务:" + taskId);
    }
}

4、定时轮询ZSET

创建一个定时任务来定期检查ZSET中是否有到期的任务:

java 复制代码
import org.springframework.scheduling.annotation.EnableScheduling;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
@Component
@EnableScheduling
public class TaskScheduler {
    // 注入DelayTaskService用于处理任务
    private final DelayTaskService delayTaskService;
    // 通过构造函数注入DelayTaskService
    @Autowired
    public TaskScheduler(DelayTaskService delayTaskService) {
        this.delayTaskService = delayTaskService;
    }
    /**
     * 定时检查并处理任务
     */
    @Scheduled(fixedRate = 1000) // 每1000毫秒执行一次
    public void checkAndProcessTasks() {
        // 调用DelayTaskService的processTasks方法
        delayTaskService.processTasks();
    }
}

DelayTaskService负责添加和处理延迟任务,而TaskScheduler负责定期调用processTasks方法来检查和处理到期的任务。

相关推荐
P.H. Infinity几秒前
【Redis】Redis实现分布式锁
redis·分布式·junit
martian6659 分钟前
Spring Boot开发三板斧:高效构建企业级应用的核心技法
java·开发语言
码农周10 分钟前
springboot Filter实现请求响应全链路拦截!完整日志监控方案
java·spring boot·后端
firepation13 分钟前
基于 springboot 的在线考试系统
java·spring boot·mysql·源码·课程设计
cherry523022 分钟前
【Java设计模式】第1章 课程导学
java·开发语言·设计模式
努力的搬砖人.22 分钟前
nginx如何实现负载均衡?
java·经验分享·后端·nginx
刘大猫.26 分钟前
遍历集合list工具
java·list·遍历list·遍历集合·集合排序·遍历对象返回匹配·遍历集合返回第一个匹配值
wuxiguala33 分钟前
【java图形化界面编程】
java·开发语言·python
Hotlogin34 分钟前
基于分布式指纹引擎的矩阵运营技术实践:突破平台风控的工程化解决方案
分布式·爬虫·线性代数·矩阵
东方雴翾36 分钟前
CSS语言的游戏AI
开发语言·后端·golang