分布式锁的本质,就是在Redis中给需要锁定的key设置一个值,这样在其他线程来访问的时候,发现这个key已经被设置了值,就会放弃或者等待。
1、设置分布式锁
注意事项:
- 要设置超时时间,以防止服务未能正常释放锁;
- 设置锁和设置超时时间的操作必须是原子性的,以防止设置锁后且设置超时时间前服务挂掉,导致锁一直被占领,不能被释放。
Redis可以通过如下方式原子性的设置超时时间:
set key_name true ex 5 nx
相关参数:
EX seconds
− 设置指定的到期时间(以秒为单位)。PX milliseconds
- 设置指定的到期时间(以毫秒为单位)。NX
- 仅在键不存在时设置键。XX
- 只有在键已存在时才设置。
2、锁释放
锁释放相关的问题:
- 锁超时自动释放,而加锁的任务还没有完成:不要在持锁期间做太重量的操作;
- 锁超时自动释放,被新的任务持有,而原加锁线程释放掉新任务加的锁:锁的值可以使用随机变量,在释放锁的时候,先检查随机变量是否相匹配;
- 上一条中,检查随机变量的值和释放锁不是原子性操作,如果期间锁经历了一次释放和重新设置,也会出问题:可以使用lua脚本,保证多个任务的原子性操作。
3、可重入性
可重入指的是线程在持有锁定情况下,可以再次请求加锁。如果Redis要支持可重入锁,那么就要对客户端的set进行包装,使用线程的Threadlocal存储当前线程持有锁的次数。