Redisson之RedissonLock源码完全解析

一、类结构与设计思想

1. 继承关系

java 复制代码
public class RedissonLock extends RedissonBaseLock

RedissonBaseLock:提供锁的基础能力(续期、解锁通知)
RedissonLock:实现具体锁逻辑(可重入、非公平)

2. 核心成员变量

java 复制代码
protected long internalLockLeaseTime;      // 锁租约时间(默认30秒)
protected final LockPubSub pubSub;         // 锁的发布订阅管理器
final CommandAsyncExecutor commandExecutor; // Redis命令执行器

二、核心方法深度解析

1. 加锁入口:lock()

java 复制代码
public void lock() {
    try {
        lock(-1, null, false);  // 无限等待,不可中断
    } catch (InterruptedException e) {
        throw new IllegalStateException();
    }
}

-1:表示无限等待

null:使用默认租约时间(Watchdog自动续期)

false:不支持中断

2. 核心加锁流程:lock(long leaseTime, TimeUnit unit, boolean interruptibly)

这是整个锁的核心逻辑:

关键代码解析:

java 复制代码
private void lock(long leaseTime, TimeUnit unit, boolean interruptibly) throws InterruptedException {
        /**
         * 获取当前线程ID,用于可重入锁识别
         * 不是用Thread.currentThread()对象,因为对象可能被GC,但ID是唯一的
         * 实战注意:线程池中线程可能被复用,但ID不变,仍能正确识别重入
         */
        long threadId = Thread.currentThread().getId();
        /**
         * -1:waitTime,表示立即返回,不等待
         * leaseTime:锁持有时间(null表示使用Watchdog自动续期)
         * unit:时间单位
         * threadId:用于可重入判断
         */
        Long ttl = tryAcquire(-1, leaseTime, unit, threadId);
        // 第一次尝试获取锁
        //为什么先try一次?快速路径(Fast Path)优化:大多数情况下锁是可用的,一次尝试就能成功,避免订阅开销。
        /**
         * null:获取成功(Lua脚本返回nil)
         * 正数:锁被占用,返回剩余生存时间(毫秒)
         * 负数:理论上不会出现(Redisson总是设置过期时间)
         * 性能优化:这里直接返回,没有后续操作,热路径(Hot Path)最短化。
         */
        if (ttl == null) { //获取成功
            return;
        }

        // 获取失败,订阅锁释放消息
        //订阅什么?
        /**
         * 订阅Redis频道:redisson_lock__channel:{lock_name}
         * 当锁释放时,持有者会向这个频道发布UNLOCK_MESSAGE
         * 为什么用CompletableFuture?
         * 异步订阅,避免阻塞当前线程。但后面会同步等待订阅完成。
         */
        CompletableFuture<RedissonLockEntry> future = subscribe(threadId);//异步订阅,避免阻塞当前线程。但后面会同步等待订阅完成。
        pubSub.timeout(future);//超时保护
        RedissonLockEntry entry;
        //防止网络分区时客户端无限等待订阅。
        /**
         * 两种等待策略:
         * getInterrupted():可中断等待,响应Thread.interrupt()
         * get():不可中断等待,忽略中断
         * 设计哲学:
         * lock():不可中断,确保锁语义完整性
         * lockInterruptibly():可中断,适合需要取消的长时间操作
         */
        if (interruptibly) {
            entry = commandExecutor.getInterrupted(future);
        } else {
            entry = commandExecutor.get(future);
        }

        try {
            while (true) {
                // 循环尝试获取锁
                /**
                 * 为什么在循环内再次tryAcquire?
                 * 双重检查(Double-Check):
                 * 第一次检查后到订阅完成前,锁可能已被释放
                 * 避免收到解锁消息后还要再等一次网络RTT
                 */
                ttl = tryAcquire(-1, leaseTime, unit, threadId);
                // lock acquired
                if (ttl == null) {// 获取成功
                    break;
                }

                // 等待锁释放信号
                //情况1:知道锁何时过期(ttl >= 0)
                /**
                 * 为什么用tryAcquire(ttl)而不是acquire()?
                 * 精确超时:最多等待锁的剩余生存时间,避免:
                 * 锁永远不会释放(客户端崩溃但未设置过期时间)
                 * 无意义的长等待
                 * 中断处理策略:
                 * 可中断模式:传播中断异常,允许业务响应取消
                 * 不可中断模式:忽略中断,继续等待,保证锁获取的原子性
                 */
                if (ttl >= 0) {
                    try {
                        entry.getLatch().tryAcquire(ttl, TimeUnit.MILLISECONDS);//信号量机制
                    } catch (InterruptedException e) {
                        if (interruptibly) {
                            throw e;
                        }
                        entry.getLatch().tryAcquire(ttl, TimeUnit.MILLISECONDS);//信号量机制
                    }
                } else {
                    //情况2/3:不知道锁何时过期(ttl < 0)
                    //理论上ttl < 0不会出现(Redisson总是设置过期时间)
                    //这是防御性编程,防止极端情况
                    //acquire() vs acquireUninterruptibly():是否响应中断
                    if (interruptibly) {
                        entry.getLatch().acquire();
                    } else {
                        entry.getLatch().acquireUninterruptibly();
                    }
                }
            }
        } finally {
            /**
             * 为什么在finally中?
             * 资源泄漏防护:
             * 获取锁成功:需要取消订阅
             * 获取锁失败(超时):需要取消订阅
             * 线程被中断:需要取消订阅
             * 发生异常:需要取消订阅
             */
            /**
             * 从订阅列表移除当前线程
             * 如果没有其他等待者,取消Redis频道订阅
             * 释放信号量资源
             */
            unsubscribe(entry, threadId);// 清理订阅 
        }
//        get(lockAsync(leaseTime, unit));
    }

3. 尝试获取锁的核心:tryLockInnerAsync()

lua 复制代码
Lua脚本解析:
-- KEYS[1]: 锁的key(如"myLock")
-- ARGV[1]: 锁的过期时间(毫秒)
-- ARGV[2]: 锁的唯一标识(UUID + threadId)

-- 情况1:锁不存在 或 当前线程已持有锁(可重入)

java 复制代码
if (redis.call('exists', KEYS[1]) == 0) or 
   (redis.call('hexists', KEYS[1], ARGV[2]) == 1) then
   
    -- 可重入锁:计数器+1
    redis.call('hincrby', KEYS[1], ARGV[2], 1);
    
    -- 设置过期时间(续期)
    redis.call('pexpire', KEYS[1], ARGV[1]);
    
    -- 返回nil表示获取锁成功
    return nil;
end;

-- 情况2:锁被其他线程持有
-- 返回锁的剩余生存时间(毫秒)
return redis.call('pttl', KEYS[1]);

4. Watchdog自动续期:scheduleExpirationRenewal()

在分布式系统中,为锁设置超时时间是必要的安全措施,防止客户端崩溃导致死锁。但这就带来了两难选择:

超时太短:业务未执行完锁就过期,其他线程获取锁导致数据不一致

超时太长:客户端崩溃后锁长时间不释放,系统可用性下降

Redisson的Watchdog机制通过自动续期+心跳保活完美解决了这个困境:

保活机制:业务执行期间自动续期,锁永不过期

安全兜底:客户端崩溃后,锁会在租约到期后自动释放

智能调度:按需启动,共享续期,最小化系统开销

(1). 全局续期映射表:EXPIRATION_RENEWAL_MAP

java 复制代码
/**
 * 锁名 → 续期条目的全局映射表
 * 
 * 设计特点:
 * 1. ConcurrentHashMap保证线程安全
 * 2. 锁粒度:每个锁名对应一个Entry
 * 3. 生命周期:从第一个线程获取锁到最后一个线程释放锁
 */
private static final ConcurrentMap<String, ExpirationEntry> 
    EXPIRATION_RENEWAL_MAP = new ConcurrentHashMap<>();

(2). 续期条目:ExpirationEntry

java 复制代码
/**
 * 锁续期管理单元,核心职责:
 * 
 * 1. 线程管理:记录所有持有该锁的线程及其重入次数
 * 2. 任务控制:持有Watchdog定时任务的引用
 * 3. 引用计数:支持可重入锁的正确续期
 */
public class ExpirationEntry {
    // LinkedHashMap保持插入顺序,保证公平性
    private final Map<Long, Integer> threadIds = new LinkedHashMap<>();
    
    // Timeout引用,用于取消定时任务
    private volatile Timeout timeout;
    
    // 线程安全的引用计数管理
    public void addThreadId(long threadId) {
        threadIds.merge(threadId, 1, Integer::sum);
    }
}

(3).scheduleExpirationRenewal方法:启动续期的入口

java 复制代码
/**
 * 启动锁的自动续期守护线程(Watchdog)
 * 
 * 设计目标:
 * 1. 并发安全:多个线程同时获取同一把锁时正确工作
 * 2. 资源共享:所有持有同一把锁的线程共享一个Watchdog
 * 3. 懒加载:只有需要时才启动续期任务
 * 
 * 触发条件:当锁获取成功且没有指定明确的租约时间时
 */
protected void scheduleExpirationRenewal(long threadId) {
    // 创建新的续期条目(可能被丢弃)
    ExpirationEntry entry = new ExpirationEntry();
    
    // 原子操作:锁名→条目的映射
    ExpirationEntry oldEntry = EXPIRATION_RENEWAL_MAP.putIfAbsent(
        getEntryName(),  // 锁的唯一标识
        entry           // 新建的条目
    );
    
    if (oldEntry != null) {
        // 情况1:锁已被其他线程持有
        // 只是增加当前线程的引用计数,共享已有的Watchdog
        oldEntry.addThreadId(threadId);
    } else {
        // 情况2:当前线程是第一个获取锁的
        // 添加线程ID,并启动Watchdog守护线程
        entry.addThreadId(threadId);
        renewExpiration();  // 启动续期循环
    }
}

(4).renewExpiration方法:递归续期循环

java 复制代码
/**
 * 创建并调度下一次续期任务
 * 
 * 核心设计:递归而非循环
 * 优势:
 * 1. 异常安全:某次续期失败不会影响后续调度
 * 2. 动态调整:每次都可以重新计算执行时间
 * 3. 资源节约:没有任务时立即停止递归
 */
private void renewExpiration() {
    // 双重检查:锁可能已被释放
    ExpirationEntry ee = EXPIRATION_RENEWAL_MAP.get(getEntryName());
    if (ee == null) {
        return;  // 锁已释放,无需续期
    }
    
    // 创建延迟任务,internalLockLeaseTime/3后执行
    // 默认30秒租约 → 每10秒续期一次
    Timeout task = commandExecutor.getConnectionManager()
        .newTimeout(new TimerTask() {
            @Override
            public void run(Timeout timeout) {
                performExpirationRenewal();
            }
        }, internalLockLeaseTime / 3, TimeUnit.MILLISECONDS);
    
    // 保存任务引用,便于后续取消
    ee.setTimeout(task);
}

(5).performExpirationRenewal:续期执行逻辑

java 复制代码
private void performExpirationRenewal() {
    // 第一层:内存状态校验
    ExpirationEntry ent = EXPIRATION_RENEWAL_MAP.get(getEntryName());
    if (ent == null) {
        return;  // 锁条目已被移除,停止续期
    }
    
    // 第二层:线程持有校验
    Long threadId = ent.getFirstThreadId();
    if (threadId == null) {
        return;  // 没有持有线程,停止续期
    }
    
    // 第三层:Redis持有权验证
    RFuture<Boolean> future = renewExpirationAsync(threadId);
    
    // 异步回调处理续期结果
    future.whenComplete((res, e) -> {
        if (e != null) {
            // 网络或Redis异常,停止续期
            log.error("Can't update lock expiration", e);
            return;
        }
        
        if (res) {
            // 续期成功,递归调用继续下一次
            renewExpiration();
        }
        // res==false表示锁已不属于当前客户端,停止续期
    });
}
续期Lua脚本(renewExpirationAsync):
java 复制代码
-- renewExpirationAsync的核心脚本
-- 参数:KEYS[1]=锁key, ARGV[1]=30000(30秒), ARGV[2]=客户端标识

-- 关键验证:锁是否仍由当前客户端持有
if (redis.call('hexists', KEYS[1], ARGV[2]) == 1) then
    -- 验证通过,续期30秒
    redis.call('pexpire', KEYS[1], ARGV[1]);
    return 1;  -- 续期成功
end;

-- 验证失败,锁已易主或不存在
return 0;  -- 续期失败

为什么需要Lua脚本的原子验证?

防止竞态条件:在检查锁状态和执行续期之间,锁可能已被其他客户端获取。

(6).续期任务的取消机制

java 复制代码
/**
 * 取消锁的自动续期
 * 
 * 触发时机:
 * 1. 锁被正常释放(unlock)
 * 2. 锁被强制释放(forceUnlock)
 * 3. 客户端关闭(shutdown)
 * 
 * 引用计数管理:
 * - 每个线程释放锁时减少计数
 * - 只有所有线程都释放锁时才取消Watchdog
 */
protected void cancelExpirationRenewal(Long threadId) {
    ExpirationEntry entry = EXPIRATION_RENEWAL_MAP.get(getEntryName());
    if (entry == null) {
        return;
    }
    
    if (threadId != null) {
        // 减少特定线程的引用计数
        Integer count = entry.threadIds.get(threadId);
        if (count != null) {
            if (count > 1) {
                // 还有重入,只减少计数
                entry.threadIds.put(threadId, count - 1);
                return;
            }
            // 计数归零,移除线程
            entry.threadIds.remove(threadId);
        }
    }
    
    // 所有线程都释放了锁
    if (threadId == null || entry.threadIds.isEmpty()) {
        // 取消定时任务
        if (entry.timeout != null) {
            entry.timeout.cancel();
        }
        // 从全局映射中移除
        EXPIRATION_RENEWAL_MAP.remove(getEntryName());
    }
}

5. 解锁核心:unlockInnerAsync()

java 复制代码
protected RFuture<Boolean> unlockInnerAsync(long threadId) {
    return evalWriteSyncedNoRetryAsync(getRawName(), LongCodec.INSTANCE, 
        RedisCommands.EVAL_BOOLEAN,
        "if (redis.call('hexists', KEYS[1], ARGV[3]) == 0) then " +
            "return nil;" +  // 锁不存在或不属于当前线程
        "end; " +
        
        "local counter = redis.call('hincrby', KEYS[1], ARGV[3], -1); " +
        
        "if (counter > 0) then " +  // 可重入次数>0,不删除锁
            "redis.call('pexpire', KEYS[1], ARGV[2]); " +
            "return 0; " +
        "else " +  // 可重入次数=0,删除锁
            "redis.call('del', KEYS[1]); " +
            "redis.call('publish', KEYS[2], ARGV[1]); " +  // 发布解锁消息
            "return 1; " +
        "end; ",
        
        Arrays.asList(getRawName(), getChannelName()),
        LockPubSub.UNLOCK_MESSAGE, 
        internalLockLeaseTime,
        getLockName(threadId));
}

6. 发布订阅机制:LockPubSub

java 复制代码
/**
 * 分布式锁的发布订阅处理器
 * 
 * 设计意图:
 * 1. 避免传统的轮询(polling)机制,减少Redis压力
 * 2. 实现事件驱动的锁等待,提高性能
 * 3. 支持多个客户端同时等待同一把锁
 * 
 * 工作原理:
 * 当线程尝试获取锁失败时,会订阅Redis频道:redisson_lock__channel:{lock_name}
 * 锁持有者释放锁时,会向该频道发布UNLOCK_MESSAGE消息
 * 所有订阅者收到消息后,竞争获取锁(避免惊群效应)
 */
public class LockPubSub extends PublishSubscribe<RedissonLockEntry> {
    
    // 普通锁释放消息标识(写锁)
    public static final Long UNLOCK_MESSAGE = 0L;
    
    // 读锁释放消息标识(用于读写锁场景)
    public static final Long READ_UNLOCK_MESSAGE = 1L;
    
    /**
     * 创建新的锁等待条目
     * 
     * 关键设计:
     * 每个锁对应一个RedissonLockEntry,所有等待该锁的线程共享这个entry
     * entry内部维护信号量(Semaphore)和监听器队列
     * 
     * @param oldEntry 旧的entry(用于连接重连时的状态恢复)
     * @return 新的RedissonLockEntry实例
     */
    @Override
    protected RedissonLockEntry createEntry(PubSubEntry<RedissonLockEntry> oldEntry) {
        return new RedissonLockEntry();
    }
    
    /**
     * 收到Redis频道消息时的回调处理
     * 
     * 核心算法:
     * 1. 从监听器队列中取出一个待执行任务(FIFO顺序)
     * 2. 执行该任务(通常是再次尝试获取锁)
     * 3. 释放信号量的一个许可,唤醒一个等待线程
     * 
     * 为什么只唤醒一个线程?
     * - 避免"惊群效应":多个线程同时被唤醒,但只有一个能获取锁
     * - 减少无效竞争:其他线程继续等待,避免CPU和Redis的无效压力
     * 
     * @param value 当前锁对应的RedissonLockEntry
     * @param message 收到的消息(UNLOCK_MESSAGE或READ_UNLOCK_MESSAGE)
     */
    @Override
    protected void onMessage(RedissonLockEntry value, Long message) {
        if (message.equals(UNLOCK_MESSAGE)) {
            // 先执行监听器任务(通常是立即尝试获取锁)
            Runnable runnable = value.getListeners().poll();
            if (runnable != null) {
                runnable.run();  // 执行获取锁的尝试
            }
            
            // 释放信号量,唤醒一个等待线程
            value.getLatch().release();  // release(1),只释放一个许可
        }
    }
}

/**
 * 锁等待条目的核心实现类
 * 
 * 双重职责:
 * 1. 管理等待线程的同步(通过信号量)
 * 2. 管理异步回调任务(通过监听器队列)
 * 
 * 数据结构设计:
 * - Semaphore latch:控制线程挂起/唤醒
 * - ConcurrentLinkedQueue<Runnable> listeners:存储待执行的异步任务
 * 
 * 并发控制:
 * 使用线程安全的数据结构,支持多线程并发访问
 * 同一把锁的所有等待线程共享同一个entry实例
 */
public class RedissonLockEntry implements PubSubEntry<RedissonLockEntry> {
    
    /**
     * 信号量(许可数为0)
     * 
     * 设计原理:
     * - 初始许可数为0:所有尝试acquire的线程都会阻塞
     * - 收到解锁消息时release(1):释放一个许可,唤醒一个线程
     * - 实现了"精准唤醒"而非"广播唤醒"
     * 
     * 为什么用Semaphore而不是Object.wait()?
     * 1. 支持超时:tryAcquire(timeout, unit)
     * 2. 支持中断:acquire()可响应中断
     * 3. 许可控制:可精确控制唤醒的线程数量
     * 4. 无需同步块:减少死锁风险
     */
    private final Semaphore latch = new Semaphore(0);
    
    /**
     * 监听器队列(先进先出)
     * 
     * 作用:
     * 1. 存储异步回调任务,通常是立即尝试获取锁的逻辑
     * 2. 保证公平性:先订阅的线程优先被唤醒(近似公平)
     * 3. 异步任务与线程唤醒解耦:先执行任务再唤醒线程
     * 
     * 为什么用ConcurrentLinkedQueue?
     * 1. 无界队列:避免任务丢失
     * 2. 线程安全:支持多生产者(等待线程)单消费者(onMessage线程)
     * 3. 高性能:无锁算法,CAS操作
     * 4. ConcurrentLinkedQueue保证FIFO顺序
     */
    private final ConcurrentLinkedQueue<Runnable> listeners = new ConcurrentLinkedQueue<>();
    
    /**
     * 阻塞获取许可(无限等待)
     * 
     * 使用场景:
     * 当锁没有设置过期时间(理论上不会出现)或采用不可中断模式时
     * 
     * 注意:此方法会阻塞当前线程,直到:
     * 1. 收到解锁消息(release()被调用)
     * 2. 线程被中断(如果使用acquireInterruptibly)
     */
    public void acquire() {
        latch.acquire();
    }
    
    /**
     * 尝试获取许可(带超时)
     * 
     * 核心用途:
     * 当锁设置了过期时间时,最多等待锁的剩余生存时间
     * 避免锁永远不释放时线程无限等待
     * 
     * @param timeout 最大等待时间
     * @param unit 时间单位
     * @return true-获取成功,false-超时
     */
    public boolean tryAcquire(long timeout, TimeUnit unit) {
        return latch.tryAcquire(timeout, unit);
    }
    
    /**
     * 释放一个许可,唤醒一个等待线程
     * 
     * 调用时机:
     * 1. LockPubSub.onMessage()收到解锁消息时
     * 2. 锁等待超时取消时(清理资源)
     * 
     * 注意:只释放一个许可,避免惊群效应
     */
    public void release() {
        latch.release();  // 等价于release(1)
    }
}

整个机制的工作原理图


"Redisson通过发布订阅模式+信号量控制实现了高效的锁等待机制,核心设计有三层:

第一层:事件驱动代替轮询

线程获取锁失败后,不是轮询Redis,而是订阅特定频道。锁释放时通过Redis Pub/Sub通知,实现了零轮询、低延迟的等待。

第二层:精准唤醒避免惊群

每个锁对应一个RedissonLockEntry,内部用Semaphore控制线程挂起。解锁时只release(1),唤醒一个线程,避免多个线程同时竞争造成的资源浪费。

第三层:异步任务与同步等待解耦

通过ConcurrentLinkedQueue管理异步回调任务,收到解锁消息时先执行任务(尝试获取锁),再唤醒线程。这种任务先行的设计提高了响应速度。

关键优化点:

1、调整subscriptionConnectionPoolSize应对高并发

2、监控等待队列长度,预防死锁

3、合理设置超时时间,平衡响应速度和资源占用"

三、关键设计模式

1. 模板方法模式

RedissonBaseLock:定义骨架(续期、解锁)
RedissonLock:实现具体逻辑

2. 命令模式

CommandAsyncExecutor commandExecutor;
所有Redis操作都封装成Command对象,支持同步/异步执行。

3. 观察者模式

entry.addListener(listener); // 添加监听器
entry.removeListener(listener); // 移除监听器

等待锁的线程注册监听器,收到解锁消息后被唤醒。

4. 工厂模式

RedissonClient client = Redisson.create(config);
RLock lock = client.getLock("myLock");

通过工厂方法创建各种分布式对象。

四、源码中的精妙设计

1. 双重检查避免重复订阅

java 复制代码
// 在lockAsync方法中
CompletableFuture<RedissonLockEntry> subscribeFuture = subscribe(currentThreadId);
pubSub.timeout(subscribeFuture);  // 设置超时

2. 超时控制链式传递

java 复制代码
public void timeout(CompletableFuture<RedissonLockEntry> future, long timeout) {
    if (future.isDone()) {
        return;
    }
    
    // 设置超时,避免无限等待
    getServiceManager().newTimeout(t -> {
        if (!future.isDone()) {
            future.completeExceptionally(new TimeoutException());
        }
    }, timeout, TimeUnit.MILLISECONDS);
}

3. 内存泄漏防护

java 复制代码
@Override
protected void cancelExpirationRenewal(Long threadId) {
    ExpirationEntry entry = EXPIRATION_RENEWAL_MAP.get(getEntryName());
    if (entry == null || !entry.hasThreadId(threadId)) {
        return;
    }
    
    // 清理Watchdog线程
    Timeout task = entry.getTimeout();
    if (task != null) {
        task.cancel();
    }
    
    EXPIRATION_RENEWAL_MAP.remove(getEntryName());
}

4. 异步回调链

java 复制代码
// 典型的异步编程模式
ttlFuture.whenComplete((ttl, e) -> {
    if (e != null) {
        result.completeExceptionally(e);
        return;
    }
    
    if (ttl == null) {
        result.complete(null);
    } else {
        // 继续下一步
    }
});

总结:

1、 整体架构

RedissonLock的核心设计围绕三个机制:1)基于Lua脚本的原子操作;2)Watchdog自动续期;3)Pub/Sub等待通知。源码中lock()方法体现了'尝试-订阅-重试'的循环模式。

2、关键方法

tryLockInnerAsync()的Lua脚本实现了可重入锁的核心逻辑,使用Redis的hash结构存储线程标识和重入次数。scheduleExpirationRenewal()创建了守护线程自动续期,解决了业务执行时间不确定的问题。

3、设计模式

代码中运用了模板方法(BaseLock定义骨架)、观察者(锁释放通知)、命令(Redis操作封装)等多种设计模式,体现了良好的架构设计。

4、细节亮点

1)使用Semaphore作为等待队列,避免忙等待;

2)超时控制链式传递,防止内存泄漏;

3)异步回调的异常传播机制保证了可靠性。

5、实战启示

从源码中学到:分布式锁要考虑网络分区、时钟跳跃、客户端崩溃等异常情况。Redisson通过Watchdog、唯一标识、原子Lua脚本等机制提供了生产级的可靠性。

END

RedissonLock的核心是一个原子Lua脚本实现的可重入锁,配合Watchdog守护线程自动续期,通过Pub/Sub机制实现高效等待。这种设计既保证了正确性,又兼顾了性能,是我们项目分布式锁的首选方案。

相关推荐
RestCloud2 小时前
智能制造的底层基建:iPaaS 如何统一 ERP、MES 与 WMS 的数据流
java·wms·erp·数据传输·ipaas·mes·集成平台
行走的陀螺仪2 小时前
高级前端 Input 公共组件设计方案(Vue3 + TypeScript)
前端·javascript·typescript·vue·组件设计方案
Yao_YongChao2 小时前
Android MVI处理副作用(Side Effect)
android·mvi·mvi副作用
guslegend2 小时前
SpringBoot源码剖析
java
皮卡龙2 小时前
Spring MVC 接收请求参数的核心
java·spring·mvc
一颗不甘坠落的流星2 小时前
【Antd】基于 Upload 组件,导入Json文件并转换为Json数据
前端·javascript·json
LYFlied3 小时前
Vue2 与 Vue3 虚拟DOM更新原理深度解析
前端·javascript·vue.js·虚拟dom
爱笑的眼睛113 小时前
FastAPI 路由系统深度探索:超越基础 CRUD 的高级模式与架构实践
java·人工智能·python·ai