本文共 1915 字,大约阅读时间需要 6 分钟。
在一些大的互联网平台,通常都会使用定时任务处理一些周期性的业务,而为了保障系统的高可用性,定时任务也会多节点部署,而解决多节点并发问题(分布式锁),大家通常会想到使用缓存,如redis,但是如果使用set / get是无法解决问题的,同样会出现并发问题,redis有专门的解决分布式并发问题的方法,就是setnx命令,很好用,下面介绍一下java实现redis分布式锁的方法。
SETNX 是『SET if Not eXists』(如果不存在,则 SET)的简写,其操作为:将 key 的值设为 value ,当且仅当 key 不存在。若给定的 key 已经存在,则 SETNX 不做任何动作。
返回值: 设置成功,返回 1 。 设置失败,返回 0 。SetNX 不具备设置过期时间的功能,所以我们需要借助 来设置,否则可能会出现死锁问题。
是基于 spring boot的项目,这是一个项目中多节点定时扣费任务的实现。
@Component@EnableSchedulingpublic class QuartzCharge { Logger logger = LogManager.getLogger("quartzCharge"); @Autowired RedisComponent redisComponent; //每每小时0分0秒执行一次 @Scheduled(cron = "0 0 * * * *") public void quartzCharge(){ //需要先查询redis的计费标记,如果有,就不计费,如果没有就计费,整点计费 logger.info(" 定时计费开始: "); //redis分布式锁,尽量要设置过期时间,防止死锁 if(!redisComponent.setNX("quartzChargeTag", "1", 10, TimeUnit.SECONDS)){ logger.info("已有执行中定时扣费任务,本次不执行!"); return; } //计费 try{ //to_do 定时业务实现 }catch(Exception e){ logger.error("定时扣费异常结束: " + e); }finally{ //任务执行完,一定要清空缓存,防止意外终止死锁 redisComponent.del("quartzChargeTag"); } logger.info("定时计费结束!"); }}
@Componentpublic class RedisComponent { @Autowired //操作字符串的template,StringRedisTemplate是RedisTemplate的一个子集 private StringRedisTemplate stringRedisTemplate; @Autowired // RedisTemplate,可以进行所有的操作 private RedisTemplate
节点一日志:
节点二日志:
看两个节点的日志,可以清楚的看到,两个节点相互执行定时任务,执行时间就在毫厘之间,谁快谁就抢到锁,一个节点挂了还有另外一个,这样就保障了系统的高可用,是不是挺酸爽的,O(∩_∩)O哈哈~
----------over--------------
转载地址:http://gcwmf.baihongyu.com/