Redis 分布式锁
TIP
分布式锁是控制分布式系统并发访问共享资源的手段。Redis 基于 SETNX 和 Lua 脚本可以实现可靠的分布式锁。
基本实现
java
// 加锁
public boolean lock(String key, String value, long expireSeconds) {
// NX: 不存在时才设置
// EX: 设置过期时间
return redis.call("SET", key, value, "NX", "EX", expireSeconds);
}
// 解锁(使用 Lua 保证原子性)
public boolean unlock(String key, String value) {
String script = "if redis.call('GET', KEYS[1]) == ARGV[1] " +
"then return redis.call('DEL', KEYS[1]) " +
"else return 0 end";
return redis.call("EVAL", script, 1, key, value);
}Redisson 框架
实际开发中使用 Redisson 封装好的锁:
java
// 1. 引入依赖
// implementation 'org.redisson:redisson-spring-boot-starter:3.20.0'
// 2. 使用 RedissonClient
@Autowired
private RedissonClient redisson;
public void businessMethod() {
RLock lock = redisson.getLock("order:" + orderId);
try {
// 尝试加锁,最多等待100秒
if (lock.tryLock(100, 10, TimeUnit.SECONDS)) {
// 业务逻辑
}
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
} finally {
if (lock.isHeldByCurrentThread()) {
lock.unlock();
}
}
}可重入锁
java
// Redisson 的可重入锁
RLock lock = redisson.getLock("myLock");
// 同一个线程可多次获取锁
lock.lock();
lock.lock(); // 可重入
// 业务代码
lock.unlock();
lock.unlock(); // 释放两次公平锁 / 读写锁
java
// 公平锁 — 按请求顺序获取
RLock fairLock = redisson.getFairLock("fairLock");
// 读写锁
RReadWriteLock rwLock = redisson.getReadWriteLock("rwLock");
RLock readLock = rwLock.readLock();
RLock writeLock = rwLock.writeLock();
// 读读不互斥,读写互斥,写写互斥WARNING
实现分布式锁需要关注:
- 原子性:加锁和设置过期时间要原子操作
- 防死锁:必须设置过期时间
- 防误删:只能删除自己的锁(通过 value 标识)
- 可重入:同一线程可重复获取