分布式读写锁 RReadWriteLock

基于 Redis 的 Redisson 分布式可重入读写锁 RReadWriteLock ,实现了 juc lock 包下的 ReadWriteLock接口。

分布式可重入读写锁允许同时有多个读锁和一个写锁处于加锁状态。

  • ReadWriteLock 可以保证一定能读到最新数据,修改期间,写锁是一个排它锁(互斥锁、独享锁),读锁是一个共享锁;

  • 写锁没释放读锁必须等待;

  • 读 + 读 :相当于无锁,并发读,只会在 Redis 中记录所有当前的读锁。他们都会同时加锁成功;

  • 写 + 读 :必须等待写锁释放;

  • 写 + 写 :阻塞;

  • 读 + 写 :阻塞,有读锁,写也需要等待;

  • 只要有写操作都必须等待;

@RestController
@RequestMapping(value = "/test")
public class TestController {

    @Autowired
    private RedissonClient redissonClient;

    // 分布式读写锁
    private static String rwLock = "rw-lock";

    /**
     * 读接口
     */
    @GetMapping("/read")
    public String readValue(@RequestParam(defaultValue = "0") int sleepTime){
        RReadWriteLock readWriteLock = redissonClient.getReadWriteLock(rwLock);
        RLock rLock = readWriteLock.readLock();
        try {
            // 读写锁
            rLock.lock();
            // 程序睡眠,模拟业务处理时间
            TimeUnit.SECONDS.sleep(sleepTime);
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            rLock.unlock();
        }
        return String.valueOf(System.currentTimeMillis());
    }

    /**
     * 写接口
     */
    @GetMapping("/write")
    public String writeValue(@RequestParam(defaultValue = "0") int sleepTime){
        RReadWriteLock readWriteLock = redissonClient.getReadWriteLock(rwLock);
        RLock rLock = readWriteLock.writeLock();
        try {
            // 加写锁
            rLock.lock();
            // 程序睡眠,模拟业务处理时间
            TimeUnit.SECONDS.sleep(sleepTime);
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            rLock.unlock();
        }
        return String.valueOf(System.currentTimeMillis());
    }

}
/**
 * Redisson 配置类
 */
@Configuration
public class RedissonConfig {

    @Value("${spring.redis.port}")
    private String port;
    @Value("${spring.redis.host}")
    private String host;
    @Value("${spring.redis.password}")
    private String password;
    @Value("${spring.redis.client-name}")
    private String clientName;

    /**
     * 所有对 Redisson 的使用都是通过 RedissonClient
     */
    @Bean(destroyMethod = "shutdown")
    public RedissonClient redisson() {
        // 1、创建配置
        Config config = new Config();
        config.useSingleServer().setAddress("redis://" + host + ":" + port).setClientName(clientName).setPassword(password);

        // 2、根据 Config 创建出 RedissonClient 实例
        RedissonClient redisson = Redisson.create(config);
        return redisson;
    }
}

测试

  • 读锁 + 读锁测试:先访问 localhost:8081/test/read?sleepTime=10,再访问 localhost:8081/test/read 不会阻塞;
  • 读锁 + 写锁测试:先访问 localhost:8081/test/read?sleepTime=10,再访问 localhost:8081/test/write 会阻塞;
  • 写锁 + 读锁测试:先访问 localhost:8081/test/write?sleepTime=10,再访问 localhost:8081/test/read 会阻塞;
  • 写锁 + 写锁测试:先访问 localhost:8081/test/write?sleepTime=10,再访问 localhost:8081/test/write 会阻塞;

看门狗避免死锁问题

如果负责储存这个分布式锁的 Redis 节点宕机以后,而且这个锁正好处于锁住的状态时,这样会产生死锁问题。为了避免这种情况的发生,Redisson 内部提供了一个监控锁的看门狗,每加一个锁默认都会设置一个 30s 的默认时间,在 Redisson 实例被关闭前,会不断的延长锁的有效期,这样可以有效避免死锁问题。

你可能感兴趣的:(分布式锁,Redission)