实现方式
分布式锁一般有三种实现方式:1、基于数据库的乐观锁;2、基于redis实现;3、基于zookeeper的分布式锁。本文内容主要基于redis实现分布式。
具备条件
确保锁可用,必须要满足一下几个条件:
1、互斥性,任意时刻只有一个用户能持有锁
2、不会产生死锁,假设某个用户在持有锁的期间由于服务崩溃或者其他原因没有主动释放锁,也能保证后续其他用户可以加锁
3、加锁和解锁必须是同一用户,B用户无法解除A用户加的锁
代码实现
1、引入Jedis组建依赖
2、加锁
这里使用key作为锁,value作为加锁的人的标识,用于后续的解锁。
(jedis的set方法中关于 NX | XX 的区别,NX是值不存在的时候才会把值成功设置进去,XX是只有值存在的时候才会把值成功设置进去)
错误的示范加锁情况一:
这里加锁和设置过期时间采用两条命令,不具备原子性,如果中途发生故障,会产生死锁。
错误的示范加锁情况二:
这种写法:第一比较麻烦;第二需要分布式部署的几台服务器的时间必须同步;第三无法保证解锁的是否和加锁的是同一个用户
3、解锁
这里使用 eval() 方法运行Lua脚本,首先获取锁对应的value值,检查是否与requestId相等,如果相等则删除锁(解锁)。
因为确保操作需要原子性,并且保证加锁和解锁的人是同一个,使用Lua脚本可以很方便的确保这两点。
解锁错误示范一:
问题:没有保证加锁人和解锁人是同一个
解锁错误示范二:
问题:多线程环境中,在获取锁之后,锁可能由于时间过期,自动释放,然后这个时候其他线程加了锁,就会导致锁的归属人发生了变化,这时候解的锁就是别人的锁。