redisson分布式锁原理

本文详细介绍了Redisson分布式锁的使用方法,包括加锁、尝试加锁和释放锁的API。深入解析了加锁源码,特别是`lockInterruptibly`方法中的锁订阅和释放机制,以及如何通过Lua脚本确保命令原子性。此外,还提到了Redisson分布式锁的特性,如看门狗定时任务和基于Redis发布订阅的锁释放通知。
摘要由CSDN通过智能技术生成

一.分布式锁的使用

使用方法:

  /**
     * 加锁,过期自动释放,时间单位传入
     * @param lockKey
     * @param unit		时间单位
     * @param leaseTime	上锁后自动释放时间
     * @return
     */
    public RLock lock(String lockKey, TimeUnit unit, long leaseTime) {
        RLock lock = redissonClient.getLock(lockKey);
        lock.lock(leaseTime, unit);
        return lock;
    }

    /**
     * 尝试获取锁
     * @param lockKey
     * @param unit		时间单位
     * @param waitTime	最多等待时间
     * @param leaseTime	上锁后自动释放时间
     * @return
     */
    public boolean tryLock(String lockKey, TimeUnit unit, long waitTime, long leaseTime) {
        RLock lock = redissonClient.getLock(lockKey);
        try {
            return lock.tryLock(waitTime, leaseTime, unit);
        } catch (InterruptedException e) {
            return false;
        }
    }

    /**
     * 释放锁
     * @param lockKey
     */
    public void unlock(String lockKey) {
        RLock lock = redissonClient.getLock(lockKey);
        lock.unlock();
    }

二.加锁源码解析:

    public void lockInterruptibly(long leaseTime, TimeUnit unit) throws InterruptedException {
        long threadId = Thread.currentThread().getId();
        //加锁,并且返回过期时间,会调用tryAcquireAsync方法
        Long ttl = this.tryAcquire(leaseTime, unit, threadId);
        if (ttl != null) {
            //获得过期时间
            /**
             订阅锁释放事件,并通过 await 方法阻塞等待锁释放,有效的解决了无效的锁申请浪费资源的问题:
             基于信息量,当锁被其它资源占用时,当前线程通过 Redis 的 channel 订阅锁的释放事件
             一旦锁释放会发消息通知待等待的线程进行竞争获取订阅.
             */
            RFuture<RedissonLockEntry> future = this.subscribe(threadId);
            //利用Redis的发布订阅来进行锁释放消息
            this.commandExecutor.syncSubscription(future);

            try {
                //在最大等待时间内尝试加锁
                while(true) {
                    ttl = this.tryAcquire(leaseTime, unit, threadId);
                    if (ttl == null) {
                        return;
                    }
                    //等待解锁信号量
                    if (ttl >= 0L) {
                        this.getEntry(threadId).getLatch().tryAcquire(ttl, TimeUnit.MILLISECONDS);
                    } else {
                        this.getEntry(threadId).getLatch().acquire();
                    }
                }
            } finally {
                this.unsubscribe(future, threadId);
            }
        }
    }

其中tryAcquire方法最后调用的是tryAcquireAsync,获取许可并且加锁方法

 //加锁方法
    private <T> RFuture<Long> tryAcquireAsync(long leaseTime, TimeUnit unit, final long threadId) {
        if (leaseTime != -1L) {
            //如果有过期时间按照过期时间执行Redis lua脚本加锁
            return this.tryLockInnerAsync(leaseTime, unit, threadId, RedisCommands.EVAL_LONG);
        } else {
            //没有过期时间,设置看门狗默认过期时间30秒
            RFuture<Long> ttlRemainingFuture = this.tryLockInnerAsync(this.commandExecutor.getConnectionManager().getCfg().getLockWatchdogTimeout(), TimeUnit.MILLISECONDS, threadId, RedisCommands.EVAL_LONG);
            //执行完lua脚本回调
            ttlRemainingFuture.addListener(new FutureListener<Long>() {
                public void operationComplete(Future<Long> future) throws Exception {
                    if (future.isSuccess()) {
                        Long ttlRemaining = (Long)future.getNow();
                        if (ttlRemaining == null) {
                            //开始看门狗定时任务,每个10秒续期key 30秒的存活时间
                            RedissonLock.this.scheduleExpirationRenewal(threadId);
                        }

                    }
                }
            });
            return ttlRemainingFuture;
        }
    }

三.redisson分布式锁特性:

看门狗 :

定时任务,每10秒执行一次,检测Redis Key是否还存在,如果存在,续约30秒

订阅:

Semaphore信号量去做来释放和获取许可,并且通过Redis发布订阅功能来订阅锁的释放消息.

lua脚本:

来保证Redis命令的原子性

锁是hash结构

大key是锁的名称,小key是锁的标识,value是被重复加锁的次数

详细加锁过程中的发布订阅过程,可以查看其他博主的文章

https://www.jb51.net/article/234625.htm

redisson其他锁类型介绍

01_redisson分布式锁源码分析_爱喝咖啡的程序员的博客-CSDN博客_redisson分布式锁源码分析

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值