Redisson分布式锁

Redisson实现分布式锁

Redisson作为操作Redis的客户端,提供了非常多强大的API,比如分布式锁的实现、限流

Redisson实现分布式锁的原理

分布式锁的必备条件

  • 互斥性
  • 防死锁
  • 可重入
  • 高性能

Redisson还具备

  • 可重试
  • 超时续约

tryLock源码(看不懂可以先看下面的原理讲解)

public boolean tryLock(long waitTime, long leaseTime, TimeUnit unit) throws InterruptedException {
        long time = unit.toMillis(waitTime);
        long current = System.currentTimeMillis();
        long threadId = Thread.currentThread().getId();
        // 获取这把锁的超时时间
        Long ttl = tryAcquire(waitTime, leaseTime, unit, threadId);
        // lock acquired 锁已经空闲,可以获取
        if (ttl == null) {
            return true;
        }
        // time是指距离等待时间过期还剩多少时间
        time -= System.currentTimeMillis() - current;
        if (time <= 0) { // deng
            acquireFailed(waitTime, unit, threadId);
            return false;
        }
        current = System.currentTimeMillis();
    	// 发布订阅(获取锁)
        CompletableFuture<RedissonLockEntry> subscribeFuture = subscribe(threadId);
        try {
            // 尝试获取锁
            subscribeFuture.get(time, TimeUnit.MILLISECONDS);
        } catch (TimeoutException e) {
			// 取消订阅
            if (!subscribeFuture.completeExceptionally(new RedisTimeoutException(
                    "Unable to acquire subscription lock after " + time + "ms. " +
                            "Try to increase 'subscriptionsPerConnection' and/or 'subscriptionConnectionPoolSize' parameters."))) {
                subscribeFuture.whenComplete((res, ex) -> {
                    if (ex == null) {  
                        unsubscribe(res, threadId);
                    }
                });
            }
            // 获取失败
            acquireFailed(waitTime, unit, threadId);
            return false;
        } catch (ExecutionException e) {
            acquireFailed(waitTime, unit, threadId);
            return false;
        }

        try {
            // 计算剩余时间
            time -= System.currentTimeMillis() - current;
            if (time <= 0) {
                acquireFailed(waitTime, unit, threadId);
                return false;
            }
        
            while (true) {// 等待时间未到继续尝试获取锁
                long currentTime = System.currentTimeMillis();
                ttl = tryAcquire(waitTime, leaseTime, unit, threadId);
                // lock acquired成功获取到锁
                if (ttl == null) {
                    return true;
                }

                time -= System.currentTimeMillis() - currentTime;
                if (time <= 0) { //等待时间到了
                    acquireFailed(waitTime, unit, threadId);
                    return false;
                }

                // waiting for message 等待消息
                currentTime = System.currentTimeMillis();
                if (ttl >= 0 && ttl < time) {//等待时间大于锁的超时时间,等待ttl时间
                    
                    commandExecutor.getNow(subscribeFuture).getLatch().tryAcquire(ttl, TimeUnit.MILLISECONDS);
                } else {// 等待时间小于锁的超时时间,等待time时间
                    commandExecutor.getNow(subscribeFuture).getLatch().tryAcquire(time, TimeUnit.MILLISECONDS);
                }
				// 继续计算剩余时间
                time -= System.currentTimeMillis() - currentTime;
                if (time <= 0) { // 超时,返回false
                    acquireFailed(waitTime, unit, threadId);
                    return false;
                }
                // 到这还没超时继续循环,直到获取到锁
            }
        } finally {
            unsubscribe(commandExecutor.getNow(subscribeFuture), threadId);
        }
      return get(tryLockAsync(waitTime, leaseTime, unit));
    }

互斥性原理

Redisson底层是使用Redis的setnx命令,而setnx是单线程命令,具有天然的互斥性

防死锁原理

假如一个线程获取到了锁,但是在程序执行的过程中宕机没有释放锁,导致其它线程都获取不到锁怎么办?

Redisson采用了Redis的setnx命令指定锁的同时,给锁添加了超时时间,所有我们可以看见tryLock(long waitTime, long leaseTime, TimeUnit unit)函数中给了程序员设置leaseTime(锁的超时时间)的参数

可重入原理

在这里插入图片描述

Redisson存储锁的结构如上图所示

其中fieid存储的是获取到锁的线程Id,而value记录的是锁的重入次数

每当线程去申请获取已经在线程手上的锁时,就会给value += 1

每当线程去释放手上的锁时,就会给value -= 1

当线程最后一次释放锁时,value = 0,意味着是真正的释放锁

在这里插入图片描述

可重试原理

Redisson采用信号量和PubSub功能来控制获取锁失败后的重试机制。当某个线程尝试获取锁但因其他线程持有而失败时,Redisson可以通过信号量和PubSub功能让该线程等待并唤醒,以重新尝试获取锁

超时续约原理

超时续约:为了解决锁超时失效的问题,Redisson引入了watchDog看门狗机制。每隔一段时间(releaseTime),watchDog将重置锁的超时时间,确保即使在高并发环境下,锁也能够及时续约,防止因锁超时而被错误地释放。

!!注意:看门狗前提没有设置leaseTime也就是锁的释放时间
在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值