分布式锁简介
分布式锁是控制分布式系统或不同系统之间共同访问共享资源的一种锁实现。
分布式锁可以保证在分布式系统中,同一操作只被一台机器上的一个线程执行,保证共享数据的一致性。
分布式锁的设计要求
- 要是可重入锁(避免死锁)
- 要有高可用的获取锁、释放锁功能
- 获取锁、释放锁的性能要好
使用redis实现分布式锁的思路
(1)setnx(String key,String value)
若返回1,说明设置成功,获取到锁;
若返回0,说明设置失败,已经有了这个key,说明其它线程持有锁,重试。
重试需要设置一个超时时间|重试次数,不能一直尝试、阻塞在这里,达到超时时间|指定次数后还未获取到锁就放弃,实现高可用。
重试可以用while(true){ }来实现,如果未获取到锁,Thread.sleep()沉睡1s后再次执行,if(重试次数达到多少)就放弃;如果获取到锁(返回1),结束循环,继续往下执行。
value可以是任意的,但为了可读性、方便调试|维护,哪个机器的哪个线程的哪个方法要获取锁,一般就以 ip|主机名+线程名+方法名 拼接为标识符,作为value。
(2)expire(String key, int seconds)
获取到锁(返回1)后,还需要用设置生存期,如果在多少秒内没有完成,比如发生机器故障、网络故障等,键值对过期,释放锁,实现高可用。
(3)del(String key)
完成业务后需要释放锁。释放锁有2种方式:del删除key,或者expire将有效期设置为0(马上过期)。
在执行业务过程中,如果发生异常,不能继续往下执行,也应该马上释放锁。
上述方法是jedis中的方法,如果使用spring data redis,对应的方法如下
Boolean redisTemplate.opsForValue().setIfAbsent(key,value) //absent,缺席、不存在。返回的是布尔值
redisTemplate.expire(key,2,TimeUnit.MINUTES) //有效期
Boolean redisTemplate.opsForValue().setIfAbsent(key,value,2,TimeUnit.MINUTES) //上面2句代码可以写成一句
redisTemplate.delete(key) //删除key