redisson分布式锁关键源码

/**
 * Redisson分布式锁核心接口,继承了Java的Lock接口
 * 提供了分布式环境下的锁操作,支持可重入、过期自动释放等特性
 */
public interface RLock extends Lock, RExpirable, RLockAsync {

    /**
     * 尝试获取锁,获取成功后锁会在指定时间后自动释放
     * 
     * @param waitTime 最多等待时间
     * @param leaseTime 锁自动释放时间
     * @param unit 时间单位
     * @return 如果获取锁成功返回true,否则返回false
     * @throws InterruptedException 如果线程被中断则抛出异常
     */
    boolean tryLock(long waitTime, long leaseTime, TimeUnit unit) throws InterruptedException;

    /**
     * 强制释放锁,不管当前锁是否被当前线程持有
     * 注意:此方法可能会释放其他线程持有的锁,使用时需谨慎
     */
    void forceUnlock();

    /**
     * 检查当前锁是否被任何线程持有
     * 
     * @return 如果锁被持有则返回true,否则返回false
     */
    boolean isLocked();

    /**
     * 检查当前锁是否被当前线程持有
     * 
     * @return 如果当前线程持有锁则返回true,否则返回false
     */
    boolean isHeldByCurrentThread();

    /**
     * 获取当前线程持有锁的次数(重入次数)
     * 
     * @return 锁的重入次数
     */
    int getHoldCount();

    /**
     * 尝试获取锁,在指定时间内如果获取到锁,会保持指定的租约时间
     * 如果租约时间到了还未释放,锁会自动释放
     * 
     * @param leaseTime 锁的租约时间
     * @param unit 时间单位
     * @return 如果获取锁成功返回true
     * @throws InterruptedException 如果线程被中断则抛出异常
     */
    boolean tryLock(long leaseTime, TimeUnit unit) throws InterruptedException;

    /**
     * 加锁,并且指定锁的自动释放时间
     * 
     * @param leaseTime 锁自动释放时间
     * @param unit 时间单位
     */
    void lock(long leaseTime, TimeUnit unit);
}

/**
 * Redisson分布式锁的默认实现类
 */
public class RedissonLock extends RedissonExpirable implements RLock {

    /**
     * 加锁操作,默认锁不会自动释放,需要手动调用unlock()
     * 内部通过Lua脚本保证加锁操作的原子性
     */
    @Override
    public void lock() {
        try {
            // 调用tryLock方法,等待时间为-1表示一直等待,租约时间为-1表示不自动释放
            lock(-1, null, false);
        } catch (InterruptedException e) {
            throw new IllegalStateException(e);
        }
    }

    /**
     * 带超时时间的加锁操作
     * 
     * @param leaseTime 锁自动释放时间
     * @param unit 时间单位
     */
    @Override
    public void lock(long leaseTime, TimeUnit unit) {
        try {
            lock(leaseTime, unit, false);
        } catch (InterruptedException e) {
            throw new IllegalStateException(e);
        }
    }

    /**
     * 尝试获取锁的核心实现
     * 
     * @param waitTime 最多等待时间
     * @param leaseTime 锁自动释放时间
     * @param unit 时间单位
     * @return 是否获取锁成功
     * @throws InterruptedException 如果线程被中断则抛出异常
     */
    @Override
    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(leaseTime, unit, threadId);
        // 如果ttl为null,表示获取锁成功
        if (ttl == null) {
            return true;
        }
        
        // 如果剩余等待时间小于等于0,返回获取失败
        time -= System.currentTimeMillis() - current;
        if (time <= 0) {
            acquireFailed(threadId);
            return false;
        }
        
        current = System.currentTimeMillis();
        
        // 订阅锁释放事件,当锁释放时会收到通知
        RFuture<RedissonLockEntry> subscribeFuture = subscribe(threadId);
        // 等待订阅完成,或者超时
        if (!subscribeFuture.await(time, TimeUnit.MILLISECONDS)) {
            // 如果订阅超时,取消订阅并返回失败
            if (!subscribeFuture.cancel(false)) {
                subscribeFuture.onComplete((res, e) -> {
                    if (e == null) {
                        unsubscribe(subscribeFuture.getNow(), threadId);
                    }
                }, Thread.currentThread().getThreadGroup());
            }
            acquireFailed(threadId);
            return false;
        }
        
        try {
            // 再次计算剩余等待时间
            time -= System.currentTimeMillis() - current;
            if (time <= 0) {
                acquireFailed(threadId);
                return false;
            }
            
            // 循环等待获取锁
            while (true) {
                long currentTime = System.currentTimeMillis();
                // 再次尝试获取锁
                ttl = tryAcquire(leaseTime, unit, threadId);
                // 成功获取锁
                if (ttl == null) {
                    return true;
                }
                
                // 计算还能等待的时间
                time -= System.currentTimeMillis() - currentTime;
                if (time <= 0) {
                    acquireFailed(threadId);
                    return false;
                }
                
                // 等待锁释放通知或者超时
                currentTime = System.currentTimeMillis();
                if (ttl >= 0 && ttl < time) {
                    // 如果锁的剩余存活时间小于等待时间,则等待ttl时间
                    getEntry(threadId).getLatch().tryAcquire(ttl, TimeUnit.MILLISECONDS);
                } else {
                    // 否则等待剩余的等待时间
                    getEntry(threadId).getLatch().tryAcquire(time, TimeUnit.MILLISECONDS);
                }
                
                // 再次计算剩余等待时间
                time -= System.currentTimeMillis() - currentTime;
                if (time <= 0) {
                    acquireFailed(threadId);
                    return false;
                }
            }
        } finally {
            // 取消订阅
            unsubscribe(subscribeFuture.getNow(), threadId);
        }
    }

    /**
     * 释放锁操作
     * 内部通过Lua脚本保证释放锁的原子性,防止误释放其他线程的锁
     */
    @Override
    public void unlock() {
        try {
            get(unlockAsync(Thread.currentThread().getId()));
        } catch (RedisException e) {
            if (e.getCause() instanceof IllegalMonitorStateException) {
                throw (IllegalMonitorStateException) e.getCause();
            } else {
                throw e;
            }
        }
    }

    /**
     * 尝试获取锁的具体实现
     * 
     * @param leaseTime 租约时间
     * @param unit 时间单位
     * @param threadId 当前线程ID
     * @return 锁的剩余存活时间,如果为null表示获取成功
     */
    private Long tryAcquire(long leaseTime, TimeUnit unit, long threadId) {
        return get(tryAcquireAsync(leaseTime, unit, threadId));
    }

    /**
     * 异步尝试获取锁
     * 
     * @param leaseTime 租约时间
     * @param unit 时间单位
     * @param threadId 当前线程ID
     * @return 异步结果,包含锁的剩余存活时间,如果为null表示获取成功
     */
    private <T> RFuture<Long> tryAcquireAsync(long leaseTime, TimeUnit unit, long threadId) {
        // 如果指定了租约时间,直接尝试获取锁
        if (leaseTime != -1) {
            return tryLockInnerAsync(leaseTime, unit, threadId, RedisCommands.EVAL_LONG);
        }
        
        // 如果没有指定租约时间,使用默认的30秒,并启动定时任务自动续期
        RFuture<Long> ttlRemainingFuture = tryLockInnerAsync(commandExecutor.getConnectionManager().getCfg().getLockWatchdogTimeout(), 
                TimeUnit.MILLISECONDS, threadId, RedisCommands.EVAL_LONG);
        
        ttlRemainingFuture.onComplete((ttlRemaining, e) -> {
            if (e != null) {
                return;
            }
            
            // 成功获取锁,启动看门狗定时续期
            if (ttlRemaining == null) {
                scheduleExpirationRenewal(threadId);
            }
        });
        return ttlRemainingFuture;
    }

    /**
     * 执行Lua脚本获取锁的核心逻辑
     * Lua脚本保证了操作的原子性
     */
    private <T> RFuture<T> tryLockInnerAsync(long leaseTime, TimeUnit unit, long threadId, RedisStrictCommand<T> command) {
        internalLockLeaseTime = unit.toMillis(leaseTime);
        
        // Lua脚本:
        // 1. 如果锁不存在,则设置锁并设置过期时间
        // 2. 如果锁存在且是当前线程持有,则增加重入次数并重置过期时间
        // 3. 否则返回锁的剩余存活时间
        return commandExecutor.evalWriteAsync(getName(), LongCodec.INSTANCE, command,
                  "if (redis.call('exists', KEYS[1]) == 0) then " +
                      "redis.call('hincrby', KEYS[1], ARGV[2], 1); " +
                      "redis.call('pexpire', KEYS[1], ARGV[1]); " +
                      "return nil; " +
                  "end; " +
                  "if (redis.call('hexists', KEYS[1], ARGV[2]) == 1) then " +
                      "redis.call('hincrby', KEYS[1], ARGV[2], 1); " +
                      "redis.call('pexpire', KEYS[1], ARGV[1]); " +
                      "return nil; " +
                  "end; " +
                  "return redis.call('pttl', KEYS[1]);",
                Collections.singletonList(getName()), internalLockLeaseTime, getLockName(threadId));
    }

    /**
     * 定时任务,用于自动续期锁的过期时间
     * 防止在持有锁期间锁过期被自动释放
     * 
     * @param threadId 线程ID
     */
    private void scheduleExpirationRenewal(long threadId) {
        ExpirationEntry entry = new ExpirationEntry();
        ExpirationEntry oldEntry = EXPIRATION_RENEWAL_MAP.putIfAbsent(getEntryName(), entry);
        if (oldEntry != null) {
            oldEntry.addThreadId(threadId);
            return;
        }
        
        // 启动定时任务,每隔internalLockLeaseTime / 3时间续期一次
        Timeout task = commandExecutor.getConnectionManager().newTimeout(new TimerTask() {
            @Override
            public void run(Timeout timeout) throws Exception {
                // 执行续期操作
                RFuture<Boolean> future = renewExpirationAsync(threadId);
                
                future.onComplete((res, e) -> {
                    EXPIRATION_RENEWAL_MAP.remove(getEntryName());
                    if (e != null) {
                        log.error("Can't update lock " + getName() + " expiration", e);
                        return;
                    }
                    
                    // 如果续期成功,继续定时续期
                    if (res) {
                        scheduleExpirationRenewal(threadId);
                    }
                });
            }
        }, internalLockLeaseTime / 3, TimeUnit.MILLISECONDS);
        
        entry.setTimeout(task);
    }
}

 

posted @ 2025-09-02 21:15  诸葛匹夫  阅读(14)  评论(0)    收藏  举报