本文目录导读:

使用Redis实现分布式锁的核心是通过原子操作和过期时间来避免死锁,以下是完整的技术方案和最佳实践。
基础实现(SET NX + 过期时间)
加锁命令
SET lock_key random_value NX PX 30000
NX:键不存在时才能设置成功PX 30000:设置30秒自动过期,防止死锁random_value:唯一随机值,用于安全释放锁
Java代码示例
import redis.clients.jedis.Jedis;
import java.util.UUID;
public class RedisDistributedLock {
private static final String LOCK_SUCCESS = "OK";
private static final Long RELEASE_SUCCESS = 1L;
private Jedis jedis;
private String lockKey;
private String requestId;
private int expireTime = 30000; // 30秒过期
public boolean tryLock(String lockKey) {
requestId = UUID.randomUUID().toString();
String result = jedis.set(lockKey, requestId, "NX", "PX", expireTime);
return LOCK_SUCCESS.equals(result);
}
public boolean unlock(String lockKey) {
// Lua脚本保证原子性
String script =
"if redis.call('get', KEYS[1]) == ARGV[1] then " +
" return redis.call('del', KEYS[1]) " +
"else " +
" return 0 " +
"end";
Object result = jedis.eval(script,
Collections.singletonList(lockKey),
Collections.singletonList(requestId));
return RELEASE_SUCCESS.equals(result);
}
}
完整避免死锁的策略
设置合理的过期时间
// 根据业务执行时间动态调整 int estimatedTime = 5000; // 预估执行时间 int expireTime = estimatedTime * 3; // 设置3倍缓冲 jedis.set(key, value, "NX", "PX", expireTime);
自动续期(看门狗模式)
public class LockWithWatchdog {
private ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(1);
private volatile boolean running = true;
public boolean tryLock(String key, int expireTime) {
if (acquireLock(key, expireTime)) {
startWatchdog(key, expireTime);
return true;
}
return false;
}
private void startWatchdog(String key, int expireTime) {
scheduler.scheduleAtFixedRate(() -> {
if (running) {
// 续期操作
jedis.expire(key, expireTime / 1000);
}
}, expireTime / 3, expireTime / 3, TimeUnit.MILLISECONDS);
}
public void unlock(String key) {
running = false;
scheduler.shutdown();
// 释放锁的Lua脚本
}
}
Redlock算法(高可用场景)
public class Redlock {
private List<Jedis> redisNodes; // 多个独立的Redis节点
public boolean tryLock(String key, int ttl) {
int n = redisNodes.size();
int quorum = n / 2 + 1;
int startTime = System.currentTimeMillis();
int lockCount = 0;
for (Jedis node : redisNodes) {
String result = node.set(key, value, "NX", "PX", ttl);
if ("OK".equals(result)) {
lockCount++;
}
}
int elapsedTime = System.currentTimeMillis() - startTime;
if (lockCount >= quorum && elapsedTime < ttl) {
// 获取锁成功
return true;
} else {
// 释放部分获取的锁
for (Jedis node : redisNodes) {
unlock(node, key, value);
}
return false;
}
}
}
最佳实践模板
完整的生产级实现
import redis.clients.jedis.Jedis;
import redis.clients.jedis.params.SetParams;
import java.util.Collections;
import java.util.UUID;
import java.util.concurrent.TimeUnit;
import java.util.function.Supplier;
public class RedisLockTemplate {
private Jedis jedis;
public <T> T executeWithLock(String lockKey,
int expireTimeMs,
int waitTimeoutMs,
Supplier<T> action) {
String requestId = UUID.randomUUID().toString();
long startTime = System.currentTimeMillis();
try {
// 自旋获取锁
while (System.currentTimeMillis() - startTime < waitTimeoutMs) {
String result = jedis.set(lockKey, requestId,
SetParams.setParams().nx().px(expireTimeMs));
if ("OK".equals(result)) {
try {
// 执行业务逻辑
return action.get();
} finally {
// 安全释放锁
releaseLock(lockKey, requestId);
}
}
// 避免忙等,稍作休眠
Thread.sleep(100);
}
throw new RuntimeException("获取锁超时");
} catch (Exception e) {
throw new RuntimeException("执行失败", e);
}
}
private boolean releaseLock(String key, String requestId) {
String script =
"if redis.call('get', KEYS[1]) == ARGV[1] then " +
" return redis.call('del', KEYS[1]) " +
"else " +
" return 0 " +
"end";
Object result = jedis.eval(script,
Collections.singletonList(key),
Collections.singletonList(requestId));
return Long.valueOf(1).equals(result);
}
}
// 使用示例
RedisLockTemplate lockTemplate = new RedisLockTemplate();
Integer result = lockTemplate.executeWithLock(
"order:123",
30000, // 锁过期时间
5000, // 等待超时时间
() -> {
// 业务逻辑
return processOrder(123);
}
);
注意事项与常见陷阱
❌ 常见错误
- 不用原子操作:先检查再删除,非原子操作可能导致误删
- 过期时间设置不合理:太短业务没完成,太长影响并发
- 使用相同的value:无法区分不同客户端,可能释放别人的锁
✅ 正确做法
- 使用Lua脚本保证原子性
- 生成唯一随机值(UUID)
- 设置合理的过期时间 + 续期机制
- 考虑时钟漂移问题(Redlock中特别重要)
性能优化建议
| 场景 | 推荐方案 |
|---|---|
| 低并发、简单需求 | SET NX + 过期时间 |
| 高并发、需要自动续期 | 看门狗模式 |
| 分布式、高可靠性 | Redlock算法 |
| 已使用Redisson | 直接使用其内置Lock |
最简可靠性方案:
// 加锁
SET key uuid NX PX 30000
// 释放锁(Lua脚本保证原子性)
if redis.call("get", KEYS[1]) == ARGV[1] then
return redis.call("del", KEYS[1])
else
return 0
end
这个方案通过过期时间防止死锁,通过Lua脚本保证原子释放,是生产环境最常用的实现方式,对于高可用场景,建议使用Redlock或直接采用Redisson等成熟框架。
版权声明:NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播