Redisson 分布式锁原理分析
示例程序
示例程序:
public class RedissonTest {public static void main(String[] args) {Config config = new Config();config.useSingleServer().setPassword("123456").setAddress("redis://127.0.0.1:6379");RedissonClient redisson = Redisson.create(config);// RLock对象RLock lock = redisson.getLock("MY_KEY");ExecutorService pool = Executors.newFixedThreadPool(5);IntStream.range(1, 5).forEach(item -> {pool.execute(() -> {try {if (lock.tryLock(2000, TimeUnit.MILLISECONDS)) {System.out.println(Thread.currentThread().getName() + "get Lock!!");if (lock.tryLock(2000, TimeUnit.MILLISECONDS)) {System.out.println(Thread.currentThread().getName() + "get Lock!!");Thread.sleep(300000);lock.unlock();}Thread.sleep(500000);lock.unlock();}} catch (Exception e) {System.out.println("error!!");}});});}
}
运行结果:
redis中的值:
原理
分布式锁实现加锁解锁都需要使用lua脚本。
利用Redis的Hash结构实现可重入。
Hash结构存值如下:
key | field | value |
---|
- key:就是分布式锁的key
- field:用于存储一个能够表示一个线程的唯一标识(Redisson使用的UUID)
- value:表示当前锁被同一个线程加锁的次数(可重入的实现方式)
下面以key为MY_KEY,field线程唯一标识为:WWSSWWWKKII99I为例,总结下加锁解锁流程:
加锁流程
加锁流程:
加锁之后,hash结构为
key | field | value |
---|---|---|
MY_KEY | WWSSWWWKKII99I | 1 |
实际的存储示例:
一个线程获取了一次:
一个线程获取了两次(可重入):
解锁流程
解锁流程:
假设当前锁的hash结构是
key | field | value |
---|---|---|
MY_KEY | WWSSWWWKKII99I | 2 |
这代表分布式锁 MY_KEY 被线程标识为 WWSSWWWKKII99I 的线程获取了两次
需要注意,整个加锁解锁的命令全都需要使用lua脚本。这样能保证操作的原子性。