别再乱用Redisson分布式锁了!这可能是你见过最标准的教程(附完整代码)

纯干货、无废话、直接可用,一文搞懂 redissonClient.getLock()

一、先上结论

ini 复制代码
RLock lock = redissonClient.getLock("order:create:" + orderId);

这行代码的作用:获取一个 Redis 分布式锁,用来解决并发重复请求、重复提交、超卖、数据不一致等问题。如果你已经会用了,建议直接跳到"坑"的部分;如果还不太熟,往下看。

二、核心概念(背下来)

1. 锁名称规则

  • 同一个 key:同一把锁
  • 不同 key:不同锁
  • 命名格式:业务模块:功能:唯一标识
  • 命名示例 :
    • order:create:1001
    • stock:deduct:SKU123
    • lock1(无业务含义)

2. 锁的三个特性

  • 互斥:同一时间只有一个线程能拿到锁
  • 阻塞:拿不到锁会等待,直到锁释放
  • 自动续期:Redisson 自带看门狗(WatchDog),任务没执行完会自动延长锁时间

三、标准代码模板(复制即用)

csharp 复制代码
String lockKey = "order:create:" + orderId;
RLock lock = redissonClient.getLock(lockKey);
try {
    // 获取锁(阻塞等待,自动续期)
    lock.lock();
    
    // ========== 需要加锁的业务逻辑 ==========
    doBusiness();
} finally {
    // 必须解锁!且要判断当前线程是否持有锁
    if (lock.isHeldByCurrentThread()) {
        lock.unlock();
    }
}

这个模板就是你项目的标准答案,没有第二种写法。

四、三种加锁方式对比

1. lock() ------ 最常用、最安全

csharp 复制代码
lock.lock();
  • 等待方式:阻塞等待,拿不到锁一直等
  • 续期机制: 自动续期(看门狗)
  • 适用场景:绝大多数业务(订单创建、库存扣减、数据更新)

2. tryLock(0, time, unit) ------ 尝试一次,拿不到就放弃

csharp 复制代码
boolean locked = lock.tryLock(0, 10, TimeUnit.SECONDS);
if (locked) {
    try {
        // 业务逻辑
    } finally {
        lock.unlock();
    }
}
  • 等待方式:不等待,立即返回
  • 续期机制: 无自动续期
  • 适用场景:防止重复请求、接口幂等校验

3. tryLock(waitTime, leaseTime, unit) ------ 等待一段时间

ini 复制代码
boolean locked = lock.tryLock(3, 10, TimeUnit.SECONDS);
  • 等待方式:等待 3 秒,拿不到返回 false
  • 锁时长:10 秒自动释放
  • 续期机制: 无自动续期

五、5条铁律(面试必问、开发必守)

规则1:必须 try-finally 包裹

  • 目的:无论业务是否报错,锁一定释放

    // 错误写法 lock.lock(); doBusiness(); lock.unlock(); // 如果业务抛异常,这行不执行 → 死锁

    // 正确写法 try { lock.lock(); doBusiness(); } finally { lock.unlock(); }

规则2:解锁前必须判断 isHeldByCurrentThread()

  • 目的:防止其他线程解锁你的锁

    // 危险写法 finally { lock.unlock(); // 如果锁已经被其他线程持有,会报错 }

    // 安全写法 finally { if (lock.isHeldByCurrentThread()) { lock.unlock(); } }

规则3:不要手动设置锁超时时间(除非你确定业务执行时间很短)

  • lock.lock(10, TimeUnit.SECONDS):业务执行超过 10 秒,锁提前释放 → 锁失效
  • lock.lock():看门狗自动续期,最安全

规则4:锁粒度越小越好

csharp 复制代码
//  锁住整个方法(粒度太大)
@Transactional
public void createOrder() {
    lock.lock();
    // 整个方法
}

//  只锁关键代码块
public void createOrder() {
    // 前置校验...
    lock.lock();
    try {
        // 只锁写操作
    } finally {
        lock.unlock();
    }
}

规则5:锁名称必须有业务意义

  • 订单创建:order:create:{orderId}
  • 库存扣减:stock:deduct:{skuId}
  • 用户签到:user:sign:{userId}:{date}

六、终极模板(企业级标准)

csharp 复制代码
@Component
public class DistributedLockService {
    @Autowired
    private RedissonClient redissonClient;

    public <T> T executeWithLock(String lockKey, Supplier<T> supplier) {
        RLock lock = redissonClient.getLock(lockKey);
        try {
            lock.lock();
            return supplier.get();
        } finally {
            if (lock.isHeldByCurrentThread()) {
                lock.unlock();
            }
        }
    }
}

// 使用方式
String result = distributedLockService.executeWithLock(
    "order:create:" + orderId, 
    () -> orderService.createOrder(orderId)
);

七、你最容易踩的5个坑

  • 不在 finally 解锁:导致死锁。解决方案:用 try-finally。
  • 不判断 isHeldByCurrentThread:其他线程解锁你的锁。解决方案:解锁前判断。
  • 手动设置 lock 时间:业务超时导致锁提前释放。解决方案:用 lock()。
  • 锁粒度太大:性能差。解决方案:只锁关键代码。
  • 锁名称重复:不同业务互相阻塞。解决方案:按规范命名。

八、一句话总结

redissonClient.getLock(redisLock) = 获取分布式锁。

使用公式:lock() + try + finally + isHeldByCurrentThread 判断。把这个公式刻在脑子里,你的分布式锁就不会出问题。

相关推荐
会编程的吕洞宾5 分钟前
Spring AI 2.0 自校正结构化输出实战:让大模型稳定吐出合格 JSON
java·人工智能·后端·spring
深蓝AI27 分钟前
Future.result 超时了,Python 线程却没停:线程池取消任务的三个陷阱
后端
suhan40 分钟前
【数据结构】三、栈和队列:6.链队列、双端队列、队列的应用(树的层次遍历、广度优先BFS、先来先服务FCFS)
数据结构·后端·算法
鸿蒙开发41 分钟前
我把自己的应用上线了:从买服务器、域名和 DNS,到备案与 HTTPS
后端·github
neoooo42 分钟前
🚀Claude Code 小技巧(二):找回会话,撤销修改
前端·人工智能·后端
数据库小学妹1 小时前
向量检索最小可运行实现:HNSW索引参数与召回率/延迟权衡
数据库·后端
姜鱼问生1 小时前
Docker Volume 备份与恢复实战:不停机迁移数据
后端·算法·架构
suhan1 小时前
【数据结构】三、栈和队列:5.顺序队列(循环队列)(初始化,判空判满,入队,出队,实例)
数据结构·后端·算法
看浪的路人1 小时前
第7讲:大模型后端服务化——Go 实现高并发 LLM Proxy / Router / Fallback
开发语言·后端·golang
suhan1 小时前
【数据结构】三、栈和队列:3.链栈(链栈栈的初始化,判空,进栈,出栈,读取栈顶,链栈实例)
数据结构·后端·算法