核心实现代码:
加锁:SET lock_key unique_value NX PX 30000
解锁:if (get(lock_key) == unique_value) { del(lock_key) }
使用Lua脚本确保原子性:
local result1 = redis.call('GET', KEYS[1])
if result1 == ARGV[1] then
redis.call('DEL', KEYS[1])
return 1
end
return 0
第一篇来源内容
在Redis中实现分布式锁最简单的方式就是使用SET命令的NX和PX选项。NX表示只有键不存在时才设置,PX表示设置过期时间(毫秒)。例如:SET product:100:lock "lock_value" NX PX 30000。这会尝试获取锁30秒。如果返回OK则加锁成功,否则失败。
解锁时要验证是自己的锁:先GET锁的值,如果匹配自己的unique_value,再DEL删除。
第二篇来源内容
常见错误1:不设置过期时间,导致死锁。如果服务宕机,锁永远不会释放。
正确做法:总是用PX或EX设置TTL,比如30秒。
常见错误2:直接DEL解锁,非原子操作。A解锁时,B刚获取锁,A的DEL会误删B的锁。
解决:用Lua脚本原子检查value并删除。
第三篇来源内容
Redlock算法是加强版,但简易实现用单节点Redis即可。加锁步骤:
1. 生成唯一ID,如UUID。
2. SET key unique_id NX PX 30000。
3. 如果失败,重试或放弃。
解锁Lua脚本:
if redis.call("get",KEYS[1])==ARGV[1] then
return redis.call("del",KEYS[1])
else
return 0
end
第四篇来源内容
自动续期:锁快过期时,用watchdog线程每10秒SET key value EX 30续期,但只有持有者能续。
Java代码示例:
String result = jedis.set(lockKey, value, "NX", "PX", expireTime);
if (!"OK".equals(result)) { return false; }
第五篇来源内容
避免误删:unique_value必须唯一,不能用固定字符串如"lock"。
用UUID或threadId+timestamp。
集群模式下,建议用Redisson库,它内置了这些逻辑,简化实现。
第六篇来源内容
测试死锁:模拟宕机不解锁,用redis-cli手动查看key和TTL。
性能:SET NX PX很快,Lua脚本也原子高效。
重入:支持嵌套加锁,用计数器,如HINCRBY lock:counter 1。
FAQ
Q: 为什么不直接用SETNX和EXPIRE分开?
A: 非原子,中间宕机锁设置了但没过期。
Q: 锁时间怎么定?
A: 业务时间1.5-2倍,加上网络延迟。
Q: 单机Redis可靠吗?
A: 开发测试够用,生产用Redlock多节点。
Q: Java怎么执行Lua?
A: jedis.eval(lua, keys, args);