前提
最近在跟进一个比较老的系统的时候,发现了所有调度任务使用了spring-context里面的@Scheduled注解和自行基于Redis封装的简易分布式锁控制任务不并发执行。为了不引入其他框架的情况下做一些简单优化,笔者花点时间去研读了一下Redis的SET命令的相关文档。
场景还原
使用@Scheduled注解实现定时任务,使用spring-data-redis提供的API实现简易的Redis分布式锁的伪代码如下:
// 每30分钟跑一次
@Scheduled(cron = "* */30 * * * ? ")
public void scheduledMethod(){
// 判断KEY存在性并且设置KEY,带超时时间5分钟
if (StringRedisTemplate#opsForValue()#hasKey("定时任务唯一字符串标识")){
StringRedisTemplate#opsForValue()#set("定时任务唯一字符串标识", "1[这里暂时可以使用任何值]", 5 , TimeUnit.MINUTES);
}
// 这里做调度正常业务逻辑
doBusiness();
// 删除KEY
StringRedisTemplate#opsForValue()#delete("定时任务唯一字符串标识");
}
上面的代码存在如下显然的缺陷:
- 如果应用部署多个节点,由于判断KEY的存在性和SET操作是两个操作(非原子操作),该定时任务有可能在同一个时刻并发执行多次。
- 如果业务逻辑执行方法doBusiness()抛出了异常,会导致删除KEY的操作无法执行,KEY会到达超时时间后被删除,这个时候相当于加锁时间长达5分钟,显然是无法接受的。
但是实际上,以上两个问题在生产环境中并没有出现过,分析一下具体原因是:
- 对于第1点,该应用在生产环境只部署了2个节点,节点的重启时间并不相同,所以从天然上避免了重复执行的问题,如果CRON表达式设计

文章探讨了在不引入额外框架的情况下,如何利用Redis的SET复合命令优化分布式锁,以解决并发执行和异常处理的问题。通过结合SET命令的EX、NX选项,实现了原子性的加锁操作,并给出了具体的Java代码示例。最后提醒在生产环境中应优先考虑使用成熟的分布式锁库,如Redisson。
最低0.47元/天 解锁文章
3028

被折叠的 条评论
为什么被折叠?



