基于setnx实现的分布式锁存在下面的问题:

1.不可重入

同一个线程无法多次获取同一把锁

2.不可重试

获取锁只尝试一次就返回false,没有重试机制

3.超时释放

锁超时释放虽然可以避免死锁,但如果是业务执行耗时较长,也会导致锁释放,存在安全隐患

4.主从一致性(主写从读)

如果Redis提供了主从集群,主从同步存在延迟,当主宕机时,如果从并同步主中的锁数据,则会出现锁实现


Redission

Redisson是一 个在Redis的基础.上实现的ava驻内存数据网格(In-Memory Data Grid) 。它不仅提供了一系列的分布式的Java常用对象,还提供了许多分布式服务,其中就包含了各种分布式锁的实现。

分布式锁优化(基于redisson实现)_锁需约

官网地址: https://redisson.org/

GitHub地址: https://github.com/redisson/redisson

引入依赖
<!--redisson-->
<dependency>
<groupId>org.redisson</groupId>
<artifactId>redisson</artifactId>
<version>3.13.6</version>
</dependency>
配置redisson java客户端
@Configuration
public class RedissonConfig {

    @Bean
    public RedissonClient redissonClient(){
        // 配置
        Config config = new Config();
        config.useSingleServer().setAddress("redis://192.168.40.128:6379").setPassword("root");
        // 创建RedissonClient对象
        return Redisson.create(config);
    }
}
使用redisson的分布式锁
private void createVoucherOrder(VoucherOrder voucherOrder) {
Long userId = voucherOrder.getUserId();
Long voucherId = voucherOrder.getVoucherId();
// 创建锁对象
RLock redisLock = redissonClient.getLock("lock:order:" + userId);
// 尝试获取锁
boolean isLock = redisLock.tryLock();
// 判断
if (!isLock) {
    // 获取锁失败,直接返回失败或者重试
    log.error("不允许重复下单!");
    return;
}
}

分布式锁优化(基于redisson实现)_锁需约_02

可重入锁

什么是可重入锁?

https://blog.csdn.net/u014571143/article/details/126357814

@Slf4j
@SpringBootTest
class RedissonTest {

    @Resource
    private RedissonClient redissonClient;

    private RLock lock;

    @BeforeEach
    void setUp() {
        lock = redissonClient.getLock("order");
    }

    @Test
    void method1() throws InterruptedException {
        // 尝试获取锁
        boolean isLock = lock.tryLock(1L, TimeUnit.SECONDS);
        if (!isLock) {
            log.error("获取锁失败 .... 1");
            return;
        }
        try {
            log.info("获取锁成功 .... 1");
            method2();
            log.info("开始执行业务 ... 1");
        } finally {
            log.warn("准备释放锁 .... 1");
            lock.unlock();
        }
    }
    void method2() {
        // 尝试获取锁
        boolean isLock = lock.tryLock();
        if (!isLock) {
            log.error("获取锁失败 .... 2");
            return;
        }
        try {
            log.info("获取锁成功 .... 2");
            log.info("开始执行业务 ... 2");
        } finally {
            log.warn("准备释放锁 .... 2");
            lock.unlock();
        }
    }
}

分布式锁优化(基于redisson实现)_锁需约_03

使用的是Redis的hash数据结构,key为线程名称,value为获取锁的次数

分布式锁优化(基于redisson实现)_watchdog_04

分布式锁优化(基于redisson实现)_redisson_05

分布式锁优化(基于redisson实现)_分布式锁_06

watchDog机制

分布式锁优化(基于redisson实现)_锁需约_07

注意:只有超时释放时间为-1时,才会开启watchDog,如果提前设置了超时释放时间,不会开启watchDog

watchDog 默认续约时间是30秒

Redisson分布式锁原理:

可重入:利用hash结构记录线程id和重入次数

可重试:利用信号量和PubSub功能实现等待、唤醒,获取锁失败的重试机制

超时续约:利用watchDog,每隔一段时间(releaseTime/3),重置超时时间