分布式锁实际上就是 synchronized 关键字,在同一时间,只能有一个线程,进入当前 同步 代码块 (修改数据)
在 redis 中一般使用 setnx (set if not exists) 指令实现,通常会搭配 del 和 TTL 使用
如果 setnx 返回 1 ,证明当前无人占用,为了避免 del 之前发生异常,导致没有正确删除,会使用 TTL 设置过期时间
当锁存在时 (已经被人占用)
可是如果 expire 指令也没有得到正确执行呢?
Redis 2.8 版本中加入了一个 可以将 set 和 expire 合并的 原子操作
set lock_hello world ex 600 nx
如果没有抢到 锁 , 会得到一个 nil
如果逻辑代码的执行时间特别的长,而且不稳定,那对于锁的 TTL 就要慎重考虑
例如:
- 张三持有了 锁
- 张三设置 TTL 10分钟
- 张三开始执行逻辑 ( 没有完成,执行中…)
- 10分钟到了
- 锁自动释放了 (张三的逻辑还没有执行完)
- 李四拿到了锁
- 李四执行逻辑
- 李四释放了锁 (这个锁是张三创建的)
这里有两个问题
- 李四在张三的逻辑结束之前拿到了 不应该 拿到的锁
- 李四释放了张三的锁
对于第二个问题可以通过将 local_key 的 value 值 设置成 随机数 来解决
张三 放入 随机数 5323 , 李四的 setnx 并不会改变这个值 (设置如果不存在),那么李四在del之前需要比较这个值是否与自己 setnx 的值一致,来决定是否删除这个值,这样每个 锁 都只能由 创建者 删除,或者 TTL 超时由系统删除