别再乱用锁了!这9种Redisson锁的正确打开方式

Redisson那么多锁,你都用对了吗?

前言

lock.png_2025-05-27 095620.jpg_2025-05-27 100543.png

上周五快下班的时候,实习生小袁抱着电脑走过来,一脸疑惑。

“师兄,有点事想请教。”他挠着头说,“我在读项目代码,发现各种地方用的锁都不一样。订单用的是 getLock(),库存模块用 getReadWriteLock(),转账那边竟然还有 getMultiLock(),看得我脑壳疼。”

我本来已经开始关电脑了,一听倒来了点兴趣:“感觉用得太复杂了?”

“是啊,为啥不能统一用一种锁呢?我也搞不清楚各自到底是干嘛的。”

这个问题问得挺好。我刚入行的时候也以为“加个锁”就完事,后来踩过不少坑才发现:锁不是越多越复杂,而是用对了才有意义。

“那就趁现在不忙,我跟你讲讲 Redisson 提供的这些锁到底该怎么选。”


1. 可重入锁(Reentrant Lock):适合大多数普通场景

特性:同一个线程可以多次获得同一把锁,不会造成死锁。

优化案例:防止重复下单

RLock lock = redissonClient.getLock("order:lock:" + userId);
lock.lock();
try {
    if (!hasOrdered(userId)) {
        createOrder(userId);
    }
} finally {
    lock.unlock();
}

适合业务逻辑简单、只需防止并发执行的场景,比如防止重复下单、重复提交任务。


2. 公平锁(Fair Lock):保证先来先得

特性:维护请求队列,严格按顺序获得锁。

优化案例:按顺序处理订单

RLock fairLock = redissonClient.getFairLock("order:fairLock");
fairLock.lock();
try {
    processOrder(orderId);
} finally {
    fairLock.unlock();
}

适用于对顺序敏感的场景,如排队叫号、按用户提交顺序处理请求。


3. 联锁(MultiLock):多个资源同时加锁

特性:原子性地锁定多个资源,避免死锁。

优化案例:跨账户转账

RLock fromLock = redissonClient.getLock("account:" + fromId);
RLock toLock = redissonClient.getLock("account:" + toId);
RLock multiLock = redissonClient.getMultiLock(fromLock, toLock);
multiLock.lock();
try {
    transfer(fromId, toId, amount);
} finally {
    multiLock.unlock();
}

适合多个资源需要一致性修改的场景,如转账、合并库存等。


4. 红锁(RedLock):高可用分布式锁

特性:在多个独立 Redis 节点上加锁,需大多数节点成功。

优化案例:金融系统中的敏感操作

RLock lock1 = redissonClient1.getLock("txnLock");
RLock lock2 = redissonClient2.getLock("txnLock");
RLock lock3 = redissonClient3.getLock("txnLock");
RLock redLock = redisson.getRedLock(lock1, lock2, lock3);
redLock.lock();
try {
    processCriticalTransaction();
} finally {
    redLock.unlock();
}

适用于容忍部分 Redis 节点故障仍能保持锁有效的场景,如金融级系统。


5. 读写锁(ReadWrite Lock):提升读取性能

特性:读锁可共享,写锁独占。读多写少场景非常高效。

优化案例:商品详情缓存更新

RReadWriteLock rwLock = redissonClient.getReadWriteLock("product:" + productId);
RLock readLock = rwLock.readLock();
readLock.lock();
try {
    Product data = getFromCache(productId);
    display(data);
} finally {
    readLock.unlock();
}

读多写少场景极为常见,如配置、商品信息、用户画像等缓存场景。


6. 信号量(Semaphore):用于限流控制

特性:控制可并发访问的资源数量。

优化案例:限制同时处理的订单数

RSemaphore semaphore = redissonClient.getSemaphore("order:limit");
semaphore.trySetPermits(100);
semaphore.acquire();
try {
    handleOrderRequest();
} finally {
    semaphore.release();
}

适合控制并发量,如限流接口、线程池、数据库连接池等。


7. 可过期信号量(PermitExpirableSemaphore):防止资源泄漏

特性:许可证具有有效期,自动回收。

优化案例:调用第三方服务时自动释放

RPermitExpirableSemaphore expSemaphore = redissonClient.getPermitExpirableSemaphore("api:access");
expSemaphore.trySetPermits(5);
String permitId = expSemaphore.acquire(10, TimeUnit.SECONDS);
try {
    callExternalAPI();
} finally {
    if (permitId != null) {
        expSemaphore.release(permitId);
    }
}

适合不确定是否能正常释放许可证的场景,例如网络调用失败、中断等。


8. 闭锁(CountDownLatch):等待多个任务完成

特性:线程等待直到其他线程完成任务。

优化案例:服务启动依赖多个模块初始化

RCountDownLatch latch = redissonClient.getCountDownLatch("startup:latch");
latch.trySetCount(3);

// 在子模块初始化完成后调用
latch.countDown();

// 在主线程中等待
latch.await();

用于分布式任务聚合、服务初始化同步等场景。


9. 自旋锁(Spin Lock):超短临界区的锁优化

特性:不停尝试获取锁,不休眠,占用CPU。

优化案例:高频短操作,如内存计数

RSpinLock spinLock = redissonClient.getSpinLock("counter:lock");
spinLock.lock();
try {
    incrementInMemory();
} finally {
    spinLock.unlock();
}

适合执行时间极短的操作,尽量避免在分布式系统中使用。


锁的组合使用建议

组合使用锁是提高系统性能与可靠性的重要手段。

优化案例:读操作限流 + 保证一致性

RSemaphore semaphore = redissonClient.getSemaphore("query:limit");
RReadWriteLock rwLock = redissonClient.getReadWriteLock("data:lock");

semaphore.acquire();
rwLock.readLock().lock();
try {
    queryData();
} finally {
    rwLock.readLock().unlock();
    semaphore.release();
}

注意顺序

  • 获取锁顺序:限流 → 业务锁
  • 释放顺序:业务锁 → 限流

避免因锁顺序错误导致死锁。


性能对比与选型建议

类型特性场景推荐性能
可重入锁最常用,简单易用防重复操作、普通业务⭐⭐⭐⭐⭐
公平锁严格顺序排队系统、先到先服务⭐⭐⭐
读写锁分离读写,提升性能缓存、配置、商品信息⭐⭐⭐⭐
联锁同时锁多个资源转账、合并操作⭐⭐
红锁多节点高可用金融系统、分布式关键任务⭐⭐
信号量并发控制限流、连接池、批量处理⭐⭐⭐
过期信号量自动释放许可第三方服务调用⭐⭐⭐
闭锁同步等待机制初始化、分布式任务聚合⭐⭐⭐
自旋锁高频极短操作内存操作⭐⭐(需慎用)

结语

讲了这么多,小袁已经记得满纸笔记。

“现在知道项目里为什么用了这么多不同的锁了吧?”我问。

“嗯,懂了!”小袁点点头,“普通业务用可重入锁,配置多用读写锁,转账要用联锁,金融操作得靠红锁……”

“对,就是这么个理儿。”我拍了拍他的肩,“加锁不是为了复杂,而是为了稳。”

他笑了笑,准备走,又回头问:“那有没有捷径能快速掌握这些?”

我想了想,说:“多看看别人怎么用,多在项目中试试。纸上得来终觉浅,实践才是硬道理。”


如果你还在为选哪种锁而困惑,不妨对照你的场景,从这些锁里找一个“刚刚好”的就够了。不要贪多,也别怕用错。理解业务、合理选型,才是架构优化的第一步。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

@程序员小袁

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值