分布式锁 Redisson

依赖

<!-- redisson 分布式锁-->
<dependency>
    <groupId>org.redisson</groupId>
    <artifactId>redisson-spring-boot-starter</artifactId>
    <version>3.11.6</version>
</dependency>

配置

@Configuration
public class RedissonConfig {
    @Bean
    public RedissonClient getRedisson(){
        Config config = new Config();
        //单机模式  依次设置redis地址和密码
        config.useSingleServer().setAddress("redis://127.0.0.1:6379");
        config.setCodec(new StringCodec());
        return Redisson.create(config);
    }
}

测试

@Test
public void testRedssion() throws InterruptedException {
    RLock rlock = redissonClient.getLock("anyLock");

    /**
     * 获取锁最大等待时间(失败会重试)
     * 锁释放时间
     * 单位
     *
     */
    boolean tryLock = rlock.tryLock(1, 10, TimeUnit.SECONDS);
    try {
        if (tryLock) {
            System.out.println("执行业务逻辑");
        }
    } finally {
        rlock.unlock();
    }
}

可重入锁

在一个线程内可以多次获取同一把锁

  • Redisson通过锁计数实现,同一个线程加锁时,锁计数+1
  • 同一个线程释放锁时,锁计数-1,锁为0时才释放锁
  • 为了保证多条命令的原子性,必须采取lua脚本来做

锁重试机制

利用信号量和pubsub(消费订阅)实现等待和唤醒,获取锁失败的重试机制

 @Test
public void Relock() throws InterruptedException {
    RLock rlock = redissonClient.getLock("anyLock");

    /**
     * 获取锁最大等待时间(失败会重试)
     * 锁释放时间
     * 单位
     */
    // 设置重试时间10S
    boolean tryLock = rlock.tryLock(10L, 60L, TimeUnit.SECONDS);
    try {
        if (tryLock) {
            System.out.println("执行业务逻辑");
        }
    } finally {
        rlock.unlock();
    }
}

超时续约

  • leaseTime为-1 开启续约机制
    利用watchDog机制(看门狗),每隔一段时间(ReleaseTime / 3), 重置超时时间
/**
 * 获取锁最大等待时间(失败会重试)
 * 锁释放时间(-1、默认开启续约watchDog)
 * 单位
 */
//boolean tryLock = rlock.tryLock(10L, TimeUnit.SECONDS);// 默认leaseTime=-1
boolean tryLock = rlock.tryLock(10L, -1L, TimeUnit.SECONDS);
try {
    if (tryLock) {
        System.out.println("执行业务逻辑");
    }
} finally {
    rlock.unlock();
}

联锁机制

解决单台redis宕机,导致的锁失效问题

  • redis高可用时,保证锁的一致性,原理:尝试对获取每一台redis锁,全部获取到则加锁成功

配置多台redis

@Configuration
public class RedissonConfig {
    @Bean
    @Primary
    public RedissonClient redissonClient(){
        Config config = new Config();
        //单机模式  依次设置redis地址和密码
        config.useSingleServer().setAddress("redis://127.0.0.1:6379");
        return Redisson.create(config);
    }

    @Bean
    public RedissonClient redissonClient1(){
        Config config = new Config();
        //单机模式  依次设置redis地址和密码
        config.useSingleServer().setAddress("redis://127.0.0.1:6374").setPassword("123456");
        return Redisson.create(config);
    }
}

将所有锁联合成一个RedissonMultiLock


@Resource
RedissonClient redissonClient1;

@Resource
RedissonClient redissonClient2;

@Test
public void mLock() throws InterruptedException {
    RLock lock1 = redissonClient1.getLock("anyLock");
    RLock lock2 = redissonClient2.getLock("anyLock");

    RLock multiLock = redissonClient1.getMultiLock(lock1, lock2);
    boolean tryLock = multiLock.tryLock(5L, TimeUnit.SECONDS);
    try {
        if (tryLock) {
            System.out.println("执行业务逻辑");
        }
    } finally {
        multiLock.unlock();
    }
}
posted @ 2022-07-04 00:09  熊云港  阅读(67)  评论(0编辑  收藏  举报