- Redis 分布式锁命令
setnx
当且仅当 key 不存在。若给定的 key 已经存在,则 setnx
不做任何动作。setnx
是『set if not exists』(如果不存在,则 set)的简写,setnx
具有原子性。
getset
先 get 旧值,后set 新值,并返回 key 的旧值(old value),具有原子性。当 key 存在但不是字符串类型时,返回一个错误;当key 不存在的时候,返回nil ,在Java里就是 null。
expire
设置 key 的有效期
del
删除 key - 与时间戳的结合
分布式锁的值是按 系统当前时间 System.currentTimeMillis()
+Key 有效期
组成 - Redis 分布式锁流程图

- Redis 分布式锁优化版流程

这个优化版的流程这里说明一下,如果获取锁成功,那么按照流程执行业务逻辑,执行完毕,删除锁。如果没有获取到锁,继续判断时间戳,看是否可以重置并获取到锁,先 get 得到当前的值,并且比较一下当前的系统时间和得到的值得大小,如果当前时间大于值,说明锁已经过期了,接下来就执行 getset 操作,将该key的值重新设置一下,如果返回的旧值不存在,说明这个key 已经被删除了,或者这个旧值存在,并且和之前get 的值相同,说明在重置锁的过程中,锁没有发生变化,此时可以获取到锁了,接下来执行相应的业务逻辑。
@Scheduled(cron = "0 */1 * * * ?")
public void closeOrderTask() {
log.info("关闭订单定时任务启动");
long lockTimeOut = Long.parseLong(PropertiesUtil.getProperty("lock.timeout","5000"));
Long setnxResult = RedisShardedPoolUtil.setnx(Const.REDIS_LOCK.CLOSE_ORDER_TASK_LOCK, String.valueOf(System.currentTimeMillis() + lockTimeOut));
if (setnxResult != null && setnxResult.intValue() == 1) {
closeOrder(Const.REDIS_LOCK.CLOSE_ORDER_TASK_LOCK);
} else {
String lockValueA = RedisShardedPoolUtil.get(Const.REDIS_LOCK.CLOSE_ORDER_TASK_LOCK);
if (lockValueA != null && System.currentTimeMillis() > Long.parseLong(lockValueA)) {
String lockValueB = RedisShardedPoolUtil.getSet(Const.REDIS_LOCK.CLOSE_ORDER_TASK_LOCK, String.valueOf(System.currentTimeMillis() + lockTimeOut));
if (lockValueB == null || (lockValueB != null && StringUtils.equals(lockValueA, lockValueB))) {
closeOrder(Const.REDIS_LOCK.CLOSE_ORDER_TASK_LOCK);
} else {
log.info("没有获取到分布式锁:{}", Const.REDIS_LOCK.CLOSE_ORDER_TASK_LOCK);
}
} else {
log.info("没有获取到分布式锁:{}", Const.REDIS_LOCK.CLOSE_ORDER_TASK_LOCK);
}
}
log.info("关闭订单定时任务结束");
}
private void closeOrder(String lockName) {
RedisShardedPoolUtil.expire(lockName, 5);
log.info("获取{},ThreadName:{}", Const.REDIS_LOCK.CLOSE_ORDER_TASK_LOCK, Thread.currentThread().getName());
int hour = Integer.parseInt(PropertiesUtil.getProperty("close.order.task.time.out", "2"));
iOrderService.closeOrder(hour);
RedisShardedPoolUtil.del(Const.REDIS_LOCK.CLOSE_ORDER_TASK_LOCK);
log.info("释放{},ThreadName:{}", Const.REDIS_LOCK.CLOSE_ORDER_TASK_LOCK, Thread.currentThread().getName());
log.info("********************************************");
}
点击进入GitHub 查看代码