您的位置 首页 java

如何实现延迟队列

业务背景

在平时的业务中我们可能会碰到这样的需求,用户A将任务分配给用户B,如果30天后用户B还没有处理这个任务,那么系统自动将这个任务转发给用户C,或者将任务退回给任务A。

这里我们就可以使用延迟队列,我们写好转发方法或者退回方法,用户A分配任务时将时间记录放入延迟队列。当30天后用户B没有处理,我们获取从延迟队列里面获取这个记录,能获取得到,就执行转发方法或退回方法。如果30天内用户B处理了任务,那么就将延迟队列对应的时间记录删掉。

任务转办

当然延迟队列还有很多使用场景,比如用户下单30分钟还没付款,就将订单关闭、外卖平台发送订餐通知,下单成功后60s给用户推送短信等。

Redis 实现的延迟队列

我们可以使用Redis的 zset 可以用于作延迟队列, score 为延迟的时间点,获取时顺序获取端口的值,如果当前时间戳等于 score 则可取出。

至于如何使用Redis做延迟队列,有兴趣的童鞋可以看看我之前下的这篇文章:

Java 自带的延迟队列

当然使用Redis做延迟队列并投入生产,其设计还是很复杂的,这里我推荐 JDK 中的延迟队列API,在 java.util.concurrent 包下 DelayQueue

我们来看看它的使用。

首先我们直接创建一个延迟队列:

 // 延迟消息队列
 private   static  DelayQueue delayQueue = new DelayQueue();
  

系统启动后,我们先后添加两个消息:

 public static  void  producer() {
    // 添加消息
    delayQueue.put(new MyDelay(1000, "消息1"));
    delayQueue.put(new MyDelay(3000, "消息2"));
}
  

我们再来从延迟队列中获取数据:

 public static void  consumer () throws InterruptedException {
    System.out.println("开始执行时间:" +
            DateFormat.getDateTimeInstance().format(new Date()));
    while (!delayQueue.isEmpty()) {
        System.out.println(delayQueue.take());
    }
    System.out.println("结束执行时间:" +
            DateFormat.getDateTimeInstance().format(new Date()));
}
  

测试结果为:

 开始执行时间:2020-12-5 13:50:34
消息1
消息2
结束执行时间:2020-12-5 13:50:37
  

我们看到,消息2在延迟了3s后才从队列中被取出。

关于 DelayQueue 实际是基于优先队列来实现的。所谓的优先队列,出队是按照优先级来出的,并不是像传统的队列那样先进先出。优先队列底层是二叉堆,关于什么是二叉堆,有兴趣的童鞋可以去网上了解下。

下面是优先队列的示例代码:

实体 Student 的值:

 @AllArgsConstructor
@Data
public class Student {
    private  Integer  score;
    private String name;
    ...
}
  

这里我们按照 score 值从大到小出队。

代码执行结果:

 Name:Zhouzhou Level:100
Name:Lvshen Level:80
Name:Hall Level:60
  

关于其它的方式实现延迟队列

我在网上收集了几种延迟队列的实现方式:

定期轮询(数据库等)DelayQueue(JDK的API)TimerScheduledExecutorService时间轮(kafka)RabbitMQQuartzRedis ZsetKoalaJCronTabSchedulerX(阿里)有赞延迟队列

具体实现方式可以看看这篇文章:

你真的了解延时队列吗

好啦今天的文章就到这里啦!如果你的项目中有需要使用延迟队列的地方,希望这篇文章能帮助你。

文章来源:智云一二三科技

文章标题:如何实现延迟队列

文章地址:https://www.zhihuclub.com/194968.shtml

关于作者: 智云科技

热门文章

网站地图