使用redis服务的redisson架构实现分布式锁

发布于:2025-06-27 ⋅ 阅读:(23) ⋅ 点赞:(0)

加锁

/**
 * 尝试为指定的许可证 ID 获取分布式锁。如果锁已被占用,则立即抛出业务异常。
 *
 * @param licenseId 需要加锁的许可证 ID(即锁名称)
 * @return true 表示成功获取锁,但请注意:
 *          锁实际持有时间为 30 秒(或自动续期),
 *          调用方在业务完成后必须主动释放锁!
 * @throws BizException 当锁被占用或发生中断异常时抛出
 */
public Boolean addLockLicenseId(String licenseId) {
    // 1. 获取Redisson分布式锁对象:以licenseId作为锁的唯一标识
    RLock lock = redissonClient.getLock(licenseId);
    
    try {
        // 2. 尝试获取锁(核心逻辑)
        // - 等待时间(0): 不等待,立即返回获取结果
        // - 租期时间(30秒): 成功获取锁后,锁自动在30秒后过期释放
        // - leaseTime = 0 会启用看门狗自动续期(慎用,需确保解锁)
        boolean locked = lock.tryLock(0, 30, TimeUnit.SECONDS);
        
        if (locked) {
            // 3. 成功获取锁:直接返回true给调用方
            // 关键:调用方必须在处理完业务后主动调用lock.unlock()释放锁!
            //       否则30秒后锁会自动过期,但被动等待过期可能导致资源浪费
            return true;
        } else {
            // 4. 锁已被占用:抛出自定义业务异常
            // ERR_OPT_FAIL建议提示:"操作失败,请稍后重试"
            throw new BizException(MessageConstant.ERR_OPT_FAIL);
        }
    } catch (InterruptedException e) {
        // 5. 处理中断异常(重要:恢复线程中断状态)
        // - 避免中断信号被吞没导致线程无法响应停止请求
        // - 对支持可中断方法的框架(如线程池)非常关键
        Thread.currentThread().interrupt();
        throw new BizException("获取锁时被中断,请重试!");
    }
    // 注意:没有finally块释放锁!释放锁的职责转交给调用方(成功获取时)
}

解锁

/**
 * 释放指定许可证ID对应的分布式锁(仅限当前线程持有的锁)
 * 
 * <p>该方法通过Redisson客户端获取锁对象后,校验当前线程是否持有该锁,
 * 避免非法释放其他线程持有的锁导致并发安全问题。</p>
 *
 * @param licenseId 许可证ID(业务唯一标识),用于构造分布式锁的Redis键
 * 
 * @see RLock#isHeldByCurrentThread()  验证锁持有者的线程安全性
 * @see RLock#unlock()  释放锁的核心操作
 */
public void unLockLicenseId(String licenseId) {
    // 构造分布式锁的Redis键,格式:"{licenseId}"
    // 注意:此键必须与加锁时使用的键完全一致,否则无法定位同一把锁[6](@ref)
    RLock lock = redissonClient.getLock(licenseId);
    
    // 校验当前线程是否持有该锁(关键防御性检查)
    // 1. 防止释放其他线程持有的锁(避免IllegalMonitorStateException)
    // 2. 避免锁过期自动释放后的无效解锁操作[7](@ref)
    if (lock.isHeldByCurrentThread()) {
        // 仅当当前线程持有锁时执行释放操作
        // 注意:unlock()会递减锁的重入计数器,计数器归零时完全释放锁[6](@ref)
        lock.unlock();
    }
    // 若非当前线程持有锁,此处静默跳过(避免抛出异常中断主流程)
}

网站公告

今日签到

点亮在社区的每一天
去签到