Loading... 三种常见实现分布式锁的方式:Redis、Zookeeper、数据库 --- ## redis 分布式锁 ### 加锁 - setnx 命令,如果返回1表示加锁成功,否则加锁失败; - 记得要加过期时间,否则可能会出现持有锁的程序挂掉导致锁无法释放,最后出现死锁问题 - 加锁时要设置唯一的 value,比如用 UUID 生成,这样只有持有锁的线程才知道锁是它的 ```Java public class RedisTool { private static final String LOCK_SUCCESS = "OK"; private static final String SET_IF_NOT_EXIST = "NX"; private static final String SET_WITH_EXPIRE_TIME = "PX"; /** * 尝试获取分布式锁 * @param jedis Redis客户端 * @param lockKey 锁 * @param requestId 请求标识 * @param expireTime 超期时间 * @return 是否获取成功 */ public static boolean tryGetDistributedLock(Jedis jedis, String lockKey, String requestId, int expireTime) { String result = jedis.set(lockKey, requestId, SET_IF_NOT_EXIST, SET_WITH_EXPIRE_TIME, expireTime); if (LOCK_SUCCESS.equals(result)) { return true; } return false; } } ``` ### 释放锁 eval 命令执行 lua 脚本来实现 - 不能仅用 del 命令实现,否则会出现释放了别人的锁的情况;应该先比较是否是自己的锁,如果是,再释放;所以这里用 lua 脚本 - redis 的 lua 脚本将以原子性的方式的执行 ```Java public class RedisTool { private static final Long RELEASE_SUCCESS = 1L; /** * 释放分布式锁 * @param jedis Redis客户端 * @param lockKey 锁 * @param requestId 请求标识 * @return 是否释放成功 */ public static boolean releaseDistributedLock(Jedis jedis, String lockKey, String requestId) { String script = "if redis.call('get', KEYS[1]) == ARGV[1] then return redis.call('del', KEYS[1]) else return 0 end"; Object result = jedis.eval(script, Collections.singletonList(lockKey), Collections.singletonList(requestId)); if (RELEASE_SUCCESS.equals(result)) { return true; } return false; } } ``` 简单的命令参考: ```Java // 获取锁 // NX是指如果key不存在就成功,key存在返回false,PX可以指定过期时间 SET d_lock unique_value NX PX 30000 // 释放锁:通过执行一段lua脚本 // 释放锁涉及到两条指令,这两条指令不是原子性的 // 需要用到redis的lua脚本支持特性,redis执行lua脚本是原子性的 if redis.call("get",KEYS[1]) == ARGV[1] then return redis.call("del",KEYS[1]) else return 0 end ``` 补充:RedisTemplate 也封装了相关的方法,可以实现上述的加锁、解锁功能; Redission 这个 Redis 客户端也实现了分布式锁,并添加了 watch dog 看门狗机制来给锁续命; - watch dog: 创建一个守护线程,让其每隔一段时间给未释放的锁续命 扩展:分布式可重入锁 - 实现可重入,那么可以用唯一 val + version,version 就是一个 count,记录了重入锁的重入次数,当次数为0时,释放锁; --- 参考: - redis 分布式锁:[https://blog.csdn.net/yb223731/article/details/90349502](https://blog.csdn.net/yb223731/article/details/90349502) - 分布式锁的几种实现:[https://www.cnblogs.com/wei57960/p/14059772.html](https://www.cnblogs.com/wei57960/p/14059772.html) - eval 命令:[http://www.redis.cn/commands/eval.html](http://www.redis.cn/commands/eval.html) - redis 分布式锁:[https://juejin.cn/post/6844903849115779080](https://juejin.cn/post/6844903849115779080) Last modification:March 29, 2021 © Allow specification reprint Support Appreciate the author AliPayWeChat Like 0 请作者喝杯肥宅快乐水吧!
One comment
OωO