一、为什么需要分布式锁
在分布式系统 中,多个节点或服务实例可能同时修改同一份共享资源(例如数据库、库存、订单),
为防止并发修改、超卖、数据不一致 ,我们需要一种 跨节点的"互斥"机制。
在单机中可用 synchronized 或 ReentrantLock,
但在多机(分布式)环境下,它们无法保证互斥性。
这时就需要分布式锁。
⚙️ 二、Redis 分布式锁的基本原理
Redis 本身是一个单线程 、支持原子操作的 KV 数据库,非常适合实现分布式锁。
核心思想:
使用 Redis 的原子命令
SETNX(Set if Not Exists)
- 过期时间(防止死锁)
来确保在分布式环境中,同一时刻只有一个客户端能获得锁。
🔑 三、最常见的实现方式(单节点版本)
🧠 思路:
-
加锁 :使用
SET key value NX PX expireTime- NX:只有 key 不存在时才能设置成功(防止被覆盖)
- PX:设置过期时间(毫秒)
-
释放锁:只有锁的持有者才能删除锁(防止误删)
🔑 四、 Redisson 高级实现(推荐)
Redisson 是官方推荐的 Java Redis 客户端之一,封装了稳定的分布式锁逻辑
Redisson 实现了:
- 自动续期机制(Watchdog)
- 支持 RedLock 多节点锁算法
- 防止主从切换导致锁丢失
RedLock 的基本思想
假设有 5 个独立的 Redis 节点(N = 5),RedLock 的核心流程是:
-
客户端向所有 Redis 节点尝试获取锁**,每个节点的锁具有 唯一标识(UUID) 和
过期时间(TTL)。 -
获取锁成功的条件:
- 客户端在
多数节点(> N/2,比如至少3个节点)成功获取到锁。 - 并且
总耗时 < TTL。
- 客户端在
-
业务执行完毕释放锁:
- 客户端向获取成功的 Redis 节点发送解锁请求。
- 每个节点只删除与自己 UUID 匹配的锁,保证安全释放。
-
如果获取锁失败(未超过多数节点或超时),
回滚已获取的锁。
js
import org.redisson.Redisson;
import org.redisson.api.RedissonClient;
import org.redisson.config.Config;
public class RedissonManager {
private static RedissonClient redissonClient;
static {
Config config = new Config();
// Redis 集群模式配置
config.useClusterServers()
.addNodeAddress("redis://127.0.0.1:7000", "redis://127.0.0.1:7001", "redis://127.0.0.1:7002");
redissonClient = Redisson.create(config);
}
public static RedissonClient getClient() {
return redissonClient;
}
}
js
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import java.util.concurrent.TimeUnit;
public class DistributedLockExample {
public static void main(String[] args) {
RedissonClient redisson = RedissonManager.getClient();
// 获取锁对象
RLock lock = redisson.getLock("myLock");
try {
// 尝试加锁,最多等待3秒,锁超时10秒自动释放
boolean isLocked = lock.tryLock(3, 10, TimeUnit.SECONDS);
if (isLocked) {
try {
// 加锁成功,执行业务逻辑
System.out.println("获得锁,执行业务逻辑");
Thread.sleep(5000); // 模拟业务操作
} finally {
lock.unlock(); // 释放锁
System.out.println("释放锁");
}
} else {
System.out.println("获取锁失败,其他线程在执行");
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}