我们自定义的分布式锁采用的是Redis的String数据类型,也就是简单地key-value。在获取锁的时候也就是执行set local thread1 NX EX 10
,这个thread1也就是锁的标识,其目的就是将来在释放锁时会判断避免误删,只有锁时自己的才会去删除。那么这个流程是不能重入的。
首先我们来看一下可重入锁的demo:首先m1会执行获取锁的操作,如果失败会报错,如果成功会调用m2。而在m2里有尝试获取锁,在m1调用m2,所以他们是在一个线程里,一个线程两次的来获取锁,这就是锁的重入。
那在我们的分布式锁流程里,在获取锁就是设置key-value为local、thread1标识。接下来往下执行调用m2,m2会继续获取锁,那么又要执行set local thread1,因为加了NX,所以一点是失败的。所以我们是没有办法实现重入的。
参考ReentrantLock可重入锁的实现原理,它里面维护了一个阻塞队列和获得锁的次数state,在获取重入锁喉state++,运行完后–。所以我们在设计分布式锁时不仅要记录获取锁的线程,还要记录这个线程它重入锁的记录。显然String类型是不行的,所以我们需要可以存放local、thread1、state的数据结构,这摆明了就是要用Hash。获得重入锁后value++,释放锁时value–。
获取锁的Lua脚本:
释放锁的Lua:
刚才解决了我们自定义redis分布式锁的不可重入问题,但是还存在着锁时不可重试的,而且超时释放的隐患也没能得到解决,最后就是主从一致性的问题。
我们源码里面的tryLock时可以提供参数的,在给定的参数时间内如果没有获取到锁时可以不停的重新尝试获取锁,成功与否返回true和false。