Redis实现延迟队列

使用Redis实现延迟队列

实现思路

redis作为一款高性能的NoSQL数据库,具备快熟读写,高并发,数据持久化等特点,非常适用与实现延迟队列 ,redis提供了丰富的数据结构.
其中利用redis的ZSET集合 (有序集合)数据结构就可以实现一个简单的延迟队列

redis的zset数据结构中的每个元素都有一个分数score和一个值value,我们可以将任务的执行时间戳作为score,
将任务数据作为value,将任务插入到zset中,每个任务有一个唯一的id(比如订单id),以及任务执行时间(比如30min),
任务内容(比如订单超时支付系统自动取消)等信息体。然后另起一个线程,该线程会周期性地从zset中取出score最小
(即最早要执行的)的任务,如果该任务的score小于当前时间戳,则执行任务,否则等待一段时间再次检查,
直到任务可以执行,执行任务后,通过Redis的remove命令删除已经成功执行的任务即可。

详细步骤

本文将介绍如何使用Redis的Sorted Set数据结构来实现延迟队列,并提供一个完整的示例代码。同时,我们还将会给出对应的测试用例和测试结果。
如下我先给同学们概括下,针对Spring Boot项目,如何利用Redis实现延迟队列的一些实现步骤?

  1. 引入相关依赖 (集成redis)
        <!--集成redis-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-redis</artifactId>
        </dependency>
  1. 配置redis
#redis配置
Spring:
  redis:
    database: 0    #Redis数据库索引(默认为0)
    host: 127.0.0.1  #redis服务器ip,由于我是搭建在本地,固指向本地ip
    port: 6379  #redis服务器连接端口
    password:    #redis服务器连接密码(默认为空)
    # 连接池配置
    jedis.pool:
      max-active: 20      #连接池最大连接数(使用负值表示没有限制)
      max-wait: -1     #连接池最大阻塞等待时间(使用负值表示没有限制)
      max-idle: 10        #连接池中的最大空闲连接
      min-idle: 0         #连接池中的最小空闲连接
      timeout: 1000      #连接超时时间(毫秒)。我设置的是1秒

  1. 创建redis配置
@Configuration
public class RedisConfig {

    /**
     * RedisTemplate配置
     */
    @Bean("redisTemplate")
    public RedisTemplate<Object, Object> redisTemplate(RedisConnectionFactory redisConnectionFactory) {
        RedisTemplate<Object, Object> template = new RedisTemplate<>();
        template.setConnectionFactory(redisConnectionFactory);
        // 使用fastjson进行序列化处理,提高解析效率
        FastJsonRedisSerializer<Object> serializer = new FastJsonRedisSerializer<Object>(Object.class);
        // value值的序列化采用fastJsonRedisSerializer
        template.setValueSerializer(serializer);
        template.setHashValueSerializer(serializer);
        // key的序列化采用StringRedisSerializer
        template.setKeySerializer(new StringRedisSerializer());
        template.setHashKeySerializer(new StringRedisSerializer());
        template.setConnectionFactory(redisConnectionFactory);
        // 使用fastjson时需设置此项,否则会报异常not support type
        ParserConfig.getGlobalInstance().setAutoTypeSupport(true);
        return template;
    }

    /**
     * redis消息监听器容器 可以添加多个监听不同话题的redis监听器,只需要把消息监听器和相应的消息订阅处理器绑定,该消息监听器
     * 通过反射技术调用消息订阅处理器的相关方法进行一些业务处理
     *
     * @param connectionFactory
     * @return
     */
    @Bean
    RedisMessageListenerContainer container(RedisConnectionFactory connectionFactory) {

        RedisMessageListenerContainer container = new RedisMessageListenerContainer();
        container.setConnectionFactory(connectionFactory);
        return container;
    }
}
  1. 序列化
/**    
 * @Description:使用fastjson实现redis的序列化   
 */
public class FastJsonRedisSerializer<T> implements RedisSerializer<T> {

	public static final Charset DEFAULT_CHARSET = Charset.forName("UTF-8");
	 
    private Class<T> clazz;
 
    public FastJsonRedisSerializer(Class<T> clazz) {
        super();
        this.clazz = clazz;
    }
 
    @Override
    public byte[] serialize(T t) throws SerializationException {
        if (t == null) {
            return new byte[0];
        }
        return JSON.toJSONString(t, SerializerFeature.WriteClassName).getBytes(DEFAULT_CHARSET);
    }
 
    @Override
    public T deserialize(byte[] bytes) throws SerializationException {
        if (bytes == null || bytes.length <= 0) {
            return null;
        }
        String str = new String(bytes, DEFAULT_CHARSET);
        return (T) JSON.parseObject(str, clazz);
    }
}
  1. 创建消息类 DelayMessage
  • 这里定义一个消息类 , 包含消息的id,消息内容,以及到期时间(消息的执行时间) , 代码如下
@Data
@AllArgsConstructor
@NoArgsConstructor
public class DelayMessage implements Serializable {

    /**
     * 切记实例化
     */
    private static final long serialVersionUID = -7671756385477179547L;

    /**
     * 消息 id
     */
    private String id;

    /**
     * 消息内容
     */
    private String content;

    /**
     * 消息到期时间(指定当前消息在什么时间开始消费(时间戳))
     */
    private long expireTime;

}
  1. 创建延迟队列类 DelayQueue
  • 创建一个延迟队列类 , 提供,添加消息,删除消息,和获取消息的方法 , 具体代码如下
@Component
public class DelayQueue {

    /**
     * key后面拼接当前机器的内网ip : 用于集群区分,解决集群出现的并发问题
     */
    private static final String KEY = "delay_queue:" + getHostAddress();

    @Autowired
    private RedisTemplate redisTemplate;

    /**
     * 添加消息到延时队列中
     */
    public void put(DelayMessage message) {
        redisTemplate.opsForZSet().add(KEY, message, message.getExpireTime());
    }

    /**
     * 从延时队列中删除消息
     */
    public Long remove(DelayMessage message) {
        Long remove = redisTemplate.opsForZSet().remove(KEY, message);
        return remove;
    }

    /**
     * 获取延时队列中已到期的消息
     */
    public List<DelayMessage> getExpiredMessages() {
//        1 : 获取到开始时间
        long minScore = 0;
//        2 : 获取到结束时间
        long maxScore = System.currentTimeMillis();
//        3 : 获取到指定范围区间的数据列表
        Set<Object> messages = redisTemplate.opsForZSet().rangeByScore(KEY, minScore, maxScore);
        if (messages == null || messages.isEmpty()) {
            return Collections.emptyList();
        }
//        4 : 把对象进行封装,返回
        List<DelayMessage> result = new ArrayList<>();
        for (Object message : messages) {
            DelayMessage delayMessage = JSONObject.parseObject(JSON.toJSONString(message), DelayMessage.class);
            result.add(delayMessage);
        }
        return result;
    }

    /**
     * 获取地址(服务器的内网地址)(内网ip)
     *
     * @return
     */
    public static String getHostAddress() {
        InetAddress localHost = null;
        try {
            localHost = InetAddress.getLocalHost();
        } catch (
                UnknownHostException e) {
            e.printStackTrace();
        }
        return localHost.getHostAddress();
    }
}
  1. 创建 DelayMessageHandler 消息处理类
  • 创建一个消息处理累, 添加一个处理过期的消息,写个定时任务,间隔1s轮询延时队列中已到期的任务,如果获取不到为空,
    则不进行消息处理的逻辑 , 反之继续轮询
@Component
public class DelayMessageHandler {
    
    public static SimpleDateFormat dateTimeFormater = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");

    @Autowired
    private DelayQueue delayQueue;

    /**
     * 处理已到期的消息(轮询)
     */
    @Scheduled(fixedDelay = 1000)
    public void handleExpiredMessages() {
        String currentTime = getCurrentTime();
//      1 : 扫描任务,并将需要执行的任务加入到任务队列中
        List<DelayMessage> messages = delayQueue.getExpiredMessages();
        List<DelayMessage> messages_2 = delayQueue.getExpiredMessages();
        System.out.println(currentTime + " 待处理消息数量:" + messages.size());
//      2 : 开始处理消息
        if (!messages.isEmpty()) {
            for (DelayMessage message : messages) {
                    System.out.println(message.getId() + " --> 消息开始处理");
                    try {
//                      2.1.1 : 模拟睡眠3秒,任务的处理时间(实际可能会更长)
                        Thread.sleep(3000);
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                    System.out.println(message.getId() + " --> 消息处理结束");
//                2.2 : 处理完消息,删除消息
                    delayQueue.remove(message);
            }
        }
    }

    /**
     * 获取到的当前时分秒
     *
     * @return
     */
    public static String getCurrentTime() {
        String format = dateTimeFormater.format(new Date());
        return format;
    }
}

执行结果 : (我们可以看到 , 消息正在慢慢的被消费)

2023-11-03 15:06:01 待处理消息数量:0
2023-11-03 15:06:02 待处理消息数量:0
2023-11-03 15:06:03 待处理消息数量:0
2023-11-03 15:06:04 待处理消息数量:0
# 此处开始调用接口 , 往延迟队列中添加消息
2023-11-03 15:06:05 待处理消息数量:4
2023-11-03 15:06:05 :1 --> 消息开始处理
2023-11-03 15:06:05 :1 --> 消息处理结束
2023-11-03 15:06:05 :13 --> 消息开始处理
2023-11-03 15:06:05 :13 --> 消息处理结束
2023-11-03 15:06:05 :5 --> 消息开始处理
2023-11-03 15:06:05 :5 --> 消息处理结束
2023-11-03 15:06:05 :9 --> 消息开始处理
2023-11-03 15:06:05 :9 --> 消息处理结束
2023-11-03 15:06:18 待处理消息数量:12
2023-11-03 15:06:18 :10 --> 消息开始处理
2023-11-03 15:06:18 :10 --> 消息处理结束
2023-11-03 15:06:18 :14 --> 消息开始处理
2023-11-03 15:06:18 :14 --> 消息处理结束
2023-11-03 15:06:18 :2 --> 消息开始处理
2023-11-03 15:06:18 :2 --> 消息处理结束
2023-11-03 15:06:18 :6 --> 消息开始处理

此处我们会发现一个问题 , @Scheduled 注解是轮询执行的 , 如果上一个任务没执行完毕 , 定时器会等待 , 等待上一次执行完毕
也就是说 , @Scheduled 注解表示同步执行的 , 那么就会出现一个问题 , 每一个消息处理都会耗时3秒,
假设有 A B 两条消息 , 消息的过期时间是一致的 , 那么这两个消息会被同时从缓存中取出准备消费 ,假设A消息第一个开始消费 ,
那么B消息,就要等待3秒 , 等A消息执行完成,才开始消费B消息 , 那么就会出现消息堆积,延迟消费的情况 , 本来14:00就要消费的消息,等到了 14:10 才开始消费(可能会更晚) ,
如果消息量足够大的情况下 , 就会出现问题 , 内存泄漏 , 消息堆积 , 延迟消费等情况

解决办法 : 开线程去执行 (使用线程池) , 使用以下代码 , 我们消费一条消息,就需要创建一个线程去后台消费 , 就会解决了上面的问题 ,
(这里需要用到线程池,我为了偷懒 ,就简单模拟了一下)

    /**
     * 处理已到期的消息(轮询)
     */
    @Scheduled(fixedDelay = 1000)
    public void handleExpiredMessages() {
        String currentTime = getCurrentTime();
//      1 : 扫描任务,并将需要执行的任务加入到任务队列中
        List<DelayMessage> messages = delayQueue.getExpiredMessages();
        System.out.println(currentTime + " 待处理消息数量:" + messages.size());
//      2 : 开始处理消息
        if (!messages.isEmpty()) {
            for (DelayMessage message : messages) {
//                2.1 : 开启线程异步处理消息:不让处理消息的时间阻塞当前线程
                new Thread(() -> {
                    System.out.println(currentTime + " :" + message.getId() + " --> 消息开始处理");
                    try {
//                      2.1.1 : 模拟睡眠3秒,任务的处理时间(实际可能会更长)
                        Thread.sleep(3000);
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                    System.out.println(currentTime + " :" + message.getId() + " --> 消息处理结束");
//                2.2 : 处理完消息,删除消息
                    delayQueue.remove(message);
                }).start();
            }
        }
    }

执行结果 : 开启线程异步执行消息

2023-11-03 15:18:33 待处理消息数量:0
2023-11-03 15:18:34 待处理消息数量:0
2023-11-03 15:18:35 待处理消息数量:0
2023-11-03 15:18:36 待处理消息数量:4
2023-11-03 15:18:36 :1 --> 消息开始处理
2023-11-03 15:18:36 :13 --> 消息开始处理
2023-11-03 15:18:36 :5 --> 消息开始处理
2023-11-03 15:18:36 :9 --> 消息开始处理
2023-11-03 15:18:37 待处理消息数量:4
2023-11-03 15:18:37 :1 --> 消息开始处理  // 注意:(此消息被重复消费了)
2023-11-03 15:18:37 :13 --> 消息开始处理
2023-11-03 15:18:37 :5 --> 消息开始处理
2023-11-03 15:18:37 :9 --> 消息开始处理
2023-11-03 15:18:38 待处理消息数量:8
2023-11-03 15:18:38 :1 --> 消息开始处理
2023-11-03 15:18:38 :5 --> 消息开始处理
2023-11-03 15:18:38 :9 --> 消息开始处理
2023-11-03 15:18:38 :13 --> 消息开始处理
2023-11-03 15:18:38 :10 --> 消息开始处理
2023-11-03 15:18:38 :6 --> 消息开始处理
2023-11-03 15:18:38 :2 --> 消息开始处理
2023-11-03 15:18:38 :14 --> 消息开始处理
2023-11-03 15:18:36 :9 --> 消息处理结束
2023-11-03 15:18:36 :5 --> 消息处理结束
2023-11-03 15:18:36 :1 --> 消息处理结束
2023-11-03 15:18:36 :13 --> 消息处理结束

我们使用了开启新线程的方式来消费消息 , 消息延迟的问题解决了 , 但是又出现了新的问题 , 消息会出现重复消费的情况

问题的原因 : 我们第一次定时 , 取出了符合条件的4条过期的消息 , 我们开启了4个线程去执行 , 当第二秒 , 我们又获取了符合条件的消息 ,
因为第一次获取的消息执行需要时间 , 那么我们第二次拿消息的时候 , 就会有可能把第一次的4条消息 , 也拿出来 , 然后开线程再次消费 , 就会出现重复消费的情况了

解决方案 :

这个问题出现原因是 , 当前线程不知道这个消息已经被其他线程正在处理了 ,只要解决这个问题 ,
当前线程开始处理这个消息,先判断当前消息有没有被其他线程处理 , 如果正在处理,则不进行处理了 , 如果没处理,则开始进行处理

我们知道 redis删除元素的 remove() 方法 , 有一个返回值 , 表示删除的状态 ,
我们可以在消息处理前 , 先 remove() 这个消息 , 如果 remove()成功,则表示当前消息没有被消费 , 如果 remove()失败,则表示该消息已经被消费了

    /**
     * 处理已到期的消息(轮询)
     */
    @Scheduled(fixedDelay = 1000)
    public void handleExpiredMessages() {
        String currentTime = getCurrentTime();
//      1 : 扫描任务,并将需要执行的任务加入到任务队列中
        List<DelayMessage> messages = delayQueue.getExpiredMessages();
        System.out.println(currentTime + " 待处理消息数量:" + messages.size());
//      2 : 开始处理消息
        if (!messages.isEmpty()) {
            for (DelayMessage message : messages) {
//                2.1 : 处理消息:先删除消息,获取当前消息是否已经被其他人消费
                Long remove = delayQueue.remove(message);
                if (remove > 0) {
//                2.2 : 开启线程异步处理消息:不让处理消息的时间阻塞当前线程
                    new Thread(() -> {
                        System.out.println(currentTime + " :" + message.getId() + " --> 消息开始处理");
                        try {
//                      2.1.1 : 模拟睡眠3秒,任务的处理时间(实际可能会更长)
                            Thread.sleep(3000);
                        } catch (Exception e) {
                            e.printStackTrace();
                        }
                        System.out.println(currentTime + " :" + message.getId() + " --> 消息处理结束");
                    }).start();
                }
            }
        }
    }
  • 执行结果 : 我们会发现 , 重复消费的问题 , 解决了
2023-11-03 15:31:36 待处理消息数量:4
2023-11-03 15:31:36 :1 --> 消息开始处理
2023-11-03 15:31:36 :13 --> 消息开始处理
2023-11-03 15:31:36 :5 --> 消息开始处理
2023-11-03 15:31:36 :9 --> 消息开始处理
2023-11-03 15:31:37 待处理消息数量:0
2023-11-03 15:31:38 待处理消息数量:4
2023-11-03 15:31:38 :10 --> 消息开始处理
2023-11-03 15:31:38 :14 --> 消息开始处理
2023-11-03 15:31:38 :2 --> 消息开始处理
2023-11-03 15:31:38 :6 --> 消息开始处理
2023-11-03 15:31:36 :9 --> 消息处理结束
2023-11-03 15:31:36 :5 --> 消息处理结束
2023-11-03 15:31:36 :13 --> 消息处理结束
2023-11-03 15:31:36 :1 --> 消息处理结束
2023-11-03 15:31:39 待处理消息数量:0
2023-11-03 15:31:40 待处理消息数量:0
2023-11-03 15:31:38 :10 --> 消息处理结束
2023-11-03 15:31:38 :2 --> 消息处理结束
2023-11-03 15:31:38 :6 --> 消息处理结束
2023-11-03 15:31:38 :14 --> 消息处理结束
2023-11-03 15:31:41 待处理消息数量:4
2023-11-03 15:31:41 :11 --> 消息开始处理
2023-11-03 15:31:41 :15 --> 消息开始处理
2023-11-03 15:31:41 :3 --> 消息开始处理
2023-11-03 15:31:41 :7 --> 消息开始处理
2023-11-03 15:31:42 待处理消息数量:0
2023-11-03 15:31:43 待处理消息数量:0
2023-11-03 15:31:41 :7 --> 消息处理结束
2023-11-03 15:31:41 :11 --> 消息处理结束
2023-11-03 15:31:41 :3 --> 消息处理结束
2023-11-03 15:31:41 :15 --> 消息处理结束

但是还会出现问题 , 如果服务重启 , 或者服务宕机 , 那么当前执行中的消息 , 在下次服务启动的时候 , 就会出现消息丢失的情况

我给出的解决方案就是 : 创建一张临时数据表 , 当消息开始消费的时候 ,在表中添加一条记录,当消息消费成功,则把临时表中的记录删除
当服务重启 , 则把临时表中的记录,读到延迟队列中 , 就解决了消息丢失的情况

关键点

  1. 使用 缓存的key带内网ip的方式,解决了集群,多机器会出现的所有问题.
  2. 使用 后台线程,线程池,解决了消息堆积,延迟消费的问题.
  3. 使用 先删除key的方法 , 解决了消息重复消费的问题.
  4. 把当前处理的消息进行持久化,解决了消息丢失的问题.

这个只是我给出的解决方案 , 并不是完美的 , 如果想实现消息队列 , 最好是使用 RabbitMQ、RocketMQ、ActiveMQ、Kafka、ZeroMQ、MetaMq等

  • 5
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
### 回答1: 延时队列是指队列中的任务需要在一定延时后才能被执行,可以有效地解决某些任务需要延时处理的问题。Java Redis是一个基于Redis的Java客户端,它可以实现Java语言对Redis数据结构的操作,因此可以很方便地实现延时队列的功能。 Java Redis实现延时队列的主要思路是利用Redis的Sorted Set数据结构,将任务按照延时时间作为Score,任务内容作为Value,插入Sorted Set中,并设置过期时间,过期后将任务弹出并执行。具体实现步骤如下: 1. 创建一个Sorted Set,将任务插入其中,Score为任务的延时时间,Value为任务的内容。 2. 使用Redis的zremrangebyscore命令扫描Sorted Set中Score小于等于当前时间的任务并弹出,并将任务内容推送到执行队列中。 3. 设置延时任务的过期时间,过期时间为延时时间加当前时间,可以使用Redis的zadd命令添加任务时同时设置Score和过期时间。 4. 执行队列按顺序执行任务,任务执行完成后从执行队列中删除。 通过以上步骤,可以实现一个高效可靠的延时队列,可以优化系统任务调度、异步处理、消息通知等场景下的问题。 ### 回答2: Java Redis延时队列是一种常用的消息队列模式,在很多应用场景中都有应用。Java Redis延时队列通过将消息发送到Redis进行存储,在指定的时间后再将消息取出来进行处理。这个过程中,通过Redis的Sorted Set类型进行排序来保证队列中的消息有序。下面来详细介绍Java Redis延时队列实现方式。 一、Redis数据结构 Java Redis延时队列的关键在于Redis数据结构的设计。在Redis中,Sorted Set就是用来解决排序问题的。所以我们需要借助Sorted Set实现延时队列。具体来说,可以使用Redis中的zadd命令将消息发送到Sorted Set中,并按照时间顺序进行排序。Sorted Set中的元素包含值和权重,我们可以根据权重(即时间戳)来实现有序存储。 二、消息入队 消息的入队过程如下: 1. 获取消息的过期时间TTL。 2. 计算出当前的时间戳now。 3. 将消息写入到Sorted Set中,权重为now+TTL。 ```redis-cli> ZADD delay-queue (now + TTL) message``` 三、消息出队 消息出队过程如下: 1. 获取当前时间戳now。 2. 使用zrangebyscore命令从Sorted Set中获取所有权重小于等于now的元素,即过期的元素。 3. 遍历查询结果,对每个元素执行出队操作(移除元素)。 ```redis-cli> ZRANGEBYSCORE delay-queue -inf now``` 四、多线程处理 为避免在出队过程中同时处理多个过期元素时出现问题,可以使用多线程处理消息。Java的并发包中提供了Executor框架,这里可以使用ThreadPoolExecutor线程池。 五、消息重试 有时候由于网络波动等原因,在执行消息处理时可能会失败,所以需要将失败的消息重新入队。此时,可以加入重试机制,重新入队时TTL加上重试时间,即可实现延时次数的控制。 六、总结 Java Redis延时队列利用Redis的Sorted Set实现有序存储,使用多线程和重试机制解决了消息处理时的并发和失败问题,保障了消息的可靠性。在实际应用中,可以根据业务需求进行调优和扩展,如设置合理的时间间隔、增加监控和报警等。 ### 回答3: Java Redis实现延时队列可以分为以下几步: 1.将任务加入到延时队列中:首先需要将任务和对应的过期时间放入Redis的有序集合中,以过期时间为score值,任务为value。这样可以保证按照过期时间顺序进行排序,具有先进先出的特点。代码实现如下: ```java //添加任务到延时队列 public void addToDelayQueue(String taskId, long delayTime) { //计算过期时间 long expireTime = System.currentTimeMillis() + delayTime; //添加到有序集合中,score为过期时间 jedis.zadd(DELAY_QUEUE_KEY, expireTime, taskId); } ``` 2.从延时队列中取出任务:需要循环从有序集合中取出第一个score小于等于当前时间的任务,并将其从有序集合中删除。代码实现如下: ```java //获取延时队列中的任务 public void getFromDelayQueue() { while (true) { //获取第一个score小于等于当前时间的任务 Set<String> set = jedis.zrangeByScore(DELAY_QUEUE_KEY, 0, System.currentTimeMillis(), 0, 1); if (set == null || set.isEmpty()) { try { Thread.sleep(1000);//如果没有取到任务,则等待1秒 } catch (InterruptedException e) { e.printStackTrace(); } continue; } String taskId = set.iterator().next(); //删除任务 jedis.zrem(DELAY_QUEUE_KEY, taskId); //处理任务 handleTask(taskId); } } //处理任务 public void handleTask(String taskId) { //TODO: 根据taskId执行对应的任务 } ``` 3.使用Redis发布订阅机制以及线程池来处理任务:在处理任务时,可以使用Redis发布订阅机制将任务相关的信息发布到指定的频道,由相应的消费者线程池来进行任务处理,可以降低单线程处理任务的压力。代码实现如下: ```java //处理任务 public void handleTask(String taskId) { //通过发布订阅机制将任务信息发布到指定频道 jedis.publish(TASK_CHANNEL, taskId); } //消费者线程池处理任务 public void consumeTask() { JedisPubSub jedisPubSub = new JedisPubSub() { public void onMessage(String channel, String message) { //TODO: 根据message信息执行对应的任务 } }; jedis.subscribe(jedisPubSub, TASK_CHANNEL); executorService.execute(jedisPubSub::quit); } ``` 通过以上步骤,我们就可以实现Java Redis延时队列的功能,实现了任务的延迟执行。延时队列实现可以实现具有任务按照时间顺序执行,且任务可取消、可重试等特点,应用场景广泛。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

欢乐少年1904

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值