1.redis的实现方式:
一.redis所实现的锁-最简单的就是redisLock之类的,使用redis命令的setEx命令实现,会同时设置值以及设置过期时间,利用setNx非原子性
或者是使用lua脚本去保证原子性,将命令使用lua脚本写出然后一起去执行
加锁实现:SET resource_name my_random_value NX PX max-lock-time
解锁实现:if redis.get("resource_name") == " my_random_value" return redis.del("resource_name") else return 0
缺点:
- 1.过期时间设置问题,太长导致其他线程等待太久耗费性能,太短导致A持有锁,功能还没有处理完,但是锁已经被释放被B所获取,导致同一资源被多线程同时获取到
- 2.redis的主从复制问题,导致master设置的没有成功同步到slave,造成多线程并发访问同一个资源
实现注意:在使用lua脚本设置锁的时候,需要设置一个类似于随机串的值,这样能有效防止误删其他锁,也就是在解锁的时候需要验证当前锁是否是自己线程的锁
- 1.客户端1获取锁成功
- 2.客户端1在某个操作上阻塞了太长时间
- 3.设置的key过期了,锁自动释放了
- 4.客户端2获取到了对应同一个资源的锁
- 5.客户端1从阻塞中恢复过来,因为value值一样,所以执行释放锁操作时就会释放掉客户端2持有的锁,这样就会造成问题
参考:https://juejin.cn/post/6844903830442737671
zk的实现方式:
本质是在某个节点下创建一个临时有序结点,zk的机制会在A线程创建有序结点后返回他创建的节点是否是这个节点路径下的最小节点,要是最小的就会加锁成功。
下面记录一个公平锁的zk实现方式:

- 图1解释:A、B线程访问同个接口,A线程先来,先创建临时有序结点,创建完返回自己顺序,确定自己是否是第一个结点,是,那么A加锁成功

- 线程B开始访问接口,也在路径下创建临时有序结点,创建完后返回顺序,发现自己不是第一个,那么zk的watch机制天生支持,关于上一个结点的状态。

- A线程执行完毕,释放锁,会删除掉临时节点,B线程已经监听了A创建的节点,删除成功后就会通知B线程

- B线程开始重新获取顺序,判断自己是否是第一个,是那么加锁成功
由上述解释可知:此方式属于公平锁实现,底层加锁机制也是遵循AQS
zk方式创建分布式锁的问题:
线程A、B,A已经持有锁,但是由于线程A僵尸或者网络故障导致探活机制无响应,这时候服务端会认为死锁并释放掉,线程 B 抢到锁,线程 A 恢复,同时有两个线程访问共享资源。
京东自研分布式锁:cloud.tencent.com/developer/a…