java定时器引起死锁_SpringBoot集群中定时任务怎么处理可以防止死锁和重复执行...

朋友咨询了这么个事情,他们应用之前是单体应用,现在用nginx做了集群,但是项目中有定时任务,集群前一直运行稳定,集群后任务一直重复跑,这种情况怎么处理呢?

一般这种情况处理方法:

1.把定时任务拆分出来,单独作为一个项目跑,但针对老项目投入太多,一般没人愿意这么干

2.打补丁,这种方法是最常用的,在现有基础上添加条件,使得其只执行一次

打补丁的方法也有很多,可以根据需要自行选择

1).通过指定IP和端口,确保只有一个服务在跑定时任务

这种方法快捷,但是一般做了集群,不愿意这么做,一旦这个服务挂掉,定时任务就不起作用了,所以适用于对定时任务精度要求不高的

2).数据库记录定时任务执行状态,每次先从数据库抢占一个状态,谁抢到就由谁来执行

这种方法其实也是可以实现目的,但是适用于并发量小的,并发量如果过高,会发生状态抢占错误的情况,所以呢不是很可靠。但是很大程度上避免重复执行

3).利用redis数据库的单线程特点,抢占锁

这种方式最常用,效果也最好。不过利用这种方式也分多钟处理方式

(1)设置key值,服务发现有key,就暂停执行;如果没key,就开始执行定时任务,定时任务执行完毕,删除该key;

这样确保了不会重复执行,但是有可能漏执行,比如执行定时任务期间,服务挂掉,没有删除redis的key,这样以后服务都会当作别的服务占用了该key

(2)在上面的方法基础上,加个key的有效期;到时间自动删除key,重新被抢占

这样不会进入死锁,但是需要精准的设计好,有效期的时长,避免上次任务没执行完毕,就被下次任务抢占

(3)我们采取了,上面两种方式的集合,定时任务的key既有手动删除,也有通过时效自动时效

这个我们是这样做的,利用redisTemplate.opsForValue().increment(lockName,1)数字累加的方式,并同时设置有效期,这个有效期尽可能长点,因为我们主要靠定时任务执行完毕主动删除key,但是怕死锁,我们设置了失效期;同时我们利用累加,当累加数字大于3,们就认为已经死锁了,就会删除key,重新抢占;这样很大程度避免了重复执行和死锁,截止目前运行稳定,验证成功;

//任务锁public static String taskLock(String lockName){RedisTemplate redisTemplate=(RedisTemplate)SpringContextUtil.getBean(StringRedisTemplate.class);String s=redisTemplate.opsForValue().increment(lockName,1).toString();if(Long.parseLong(s)>=2){delete(lockName);}return s;}

以上是针对老项目而言,新项目最好是吧定时任务剥离处理,利用分布式定时任务框架来处理;比如利用quartz集群分布式(并发)部署解决方案

利用它拯救单体应用,应用服务挂了也不用担心了

4aa41d43096773b1787e6a874eedb254.png

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值