1.数据库轮询
该方案通常是在小型项目中使用,即通过一个线程定时的去扫描数据库,通过订单时间来判断是否有超时的订单,然后进行update或delete等操作
代码示例:
select * from '表名' where '时间字段' < '数据库存储的时间戳' and status = '未执行'
while(true){
sql;
Thread.sleep(1000);
}
1.优点:简单易行,支持集群操作
2.缺点:
- 对服务器内存消耗大
- 存在延迟,比如你每隔3分钟扫描一次,那最坏的延迟时间就是3分钟
- 假设你的订单有几千万条,每隔几分钟这样扫描一次,数据库损耗极大
2. JDK的延迟队列
该方案是利用JDK自带的DelayQueue来实现,这是一个无界阻塞队列,该队列只有在延迟期满的时候才能从中获取元素,放入DelayQueue中的对象,是必须实现Delayed接口的
代码示例:
public class JdkDelayQueue {
public static void main(String[] args) throws Exception{
DelayQueue<MyDelayed> delayQueue = new DelayQueue();
delayQueue.add(new MyDelayed("Andy",5, TimeUnit.SECONDS));
delayQueue.add(new MyDelayed("Andy_1",10, TimeUnit.SECONDS));
for (;;){
// 没有队列就就会阻塞
MyDelayed take = delayQueue.take();
take.excutue();
}
}
static class MyDelayed implements Delayed {
private String name;
private long startTime;
public MyDelayed(String name, long delayTime, TimeUnit unit) {
this.name = name;
// 当前时间毫秒值
long currentTime = System.currentTimeMillis();
// 时间转换为毫秒值
long convert = TimeUnit.MILLISECONDS.convert(delayTime, unit);
// 任务真正的执行时间
this.startTime = currentTime + convert;
}
@Override
public long getDelay(TimeUnit unit) {
long currentTime = System.currentTimeMillis();
if(startTime <= currentTime){
return 0;
}
long nextTime = startTime - currentTime;
return unit.convert(nextTime, TimeUnit.MICROSECONDS);
}
@Override
public int compareTo(Delayed o) {
MyDelayed prx = (MyDelayed) o;
MyDelayed next = this;
if (prx.startTime < next.startTime) {
return 1;
} else if (prx.startTime > next.startTime){
return -1;
}
return 0;
}
public void excutue(){
System.out.println(name + "任务执行");
}
}
}
1.优点:效率高,任务触发时间延迟低
2.缺点:
- 服务器重启后,数据全部消失,怕宕机
- 集群扩展相当麻烦
- 因为内存条件限制的原因,比如下单未付款的订单数太多,那么很容易就出现OOM异常
- 代码复杂度较高
3.netty时间轮算法
时间轮算法可以类比于时钟,如上图箭头(指针)按某一个方向按固定频率轮动,每一次跳动称为一个 tick
这样可以看出定时轮由个3个重要的属性参数,ticksPerWheel(一轮的tick数),tickDuration(一个tick的持续时间)以及 timeUnit(时间单位),例如当ticksPerWheel=60,tickDuration=1,timeUnit=秒,这就和现实中的始终的秒针走动完全类似了。
如果当前指针指在1上面,我有一个任务需要4秒以后执行,那么这个执行的线程回调或者消息将会被放在5上。那如果需要在20秒之后执行怎么办,由于这个环形结构槽数只到8,如果要20秒,指针需要多转2圈,位置是在2圈之后的5上面(20 % 8 + 1)
1.优点:效率高,任务触发时间延迟时间比delayQueue低,代码复杂度比delayQueue低
2.确定
- 服务器重启后,数据全部消失,怕宕机
- 集群扩展相当麻烦
- 因为内存条件限制的原因,比如下单未付款的订单数太多,那么很容易就出现OOM异常
4.使用消息队列
我们可以采用RabbitMQ的延时队列,RabbitMQ具有以下两个特性,可以实现延迟队列
- RabbitMQ可以针对Queue和Message设置 x-message-ttl,来控制消息的生存时间,如果超时,则消息变为dead letter
- RabbitMQ的Queue可以配置x-dead-letter-exchange 和x-dead-letter-routing-key(可选)两个参数,用来控制队列内出现了dead letter,则按照这两个参数重新路由
1.优点:高效,可以利用rabbitmq的分布式特性轻易的进行横向扩展,消息支持持久化增加了可靠性。文章来源:https://www.toymoban.com/news/detail-821155.html
2.缺点:本身的易用度要依赖于RabbitMq的运维,因为要引用RabbitMq,所以复杂度和成本变高文章来源地址https://www.toymoban.com/news/detail-821155.html
到了这里,关于延时任务的解决方案的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!