[Redisson] 如何使用redisson的锁?
如何使用
在分布式或者多线程操作Redis时,使用redisson会很方便,也有一些问题要注意。
在一个分布式环境运行的方法中,RLock的一般使用情况:
String lockKey = "abc"; //指定一个锁名称
RLock rLock = redissonClient.getLock(lockKey); //获取一个锁
try {
rLock.lock(); //加锁
} finally {
rLock.unlock(); //解锁
}
这里lockKey的值是"abc",redisson会在redis中存一个以"abc"为键的hash类型的值:
> type lock
hash
简单的情况下,里面的内容:
> hgetall lock
1) "25bea362-174c-4e31-aaab-046e3d138c2e:64"
2) "1"
解释:
"25bea362-174c-4e31-aaab-046e3d138c2e:64":这是hash
字段的键,表示这个分布式锁的名称。25bea362-174c-4e31-aaab-046e3d138c2e
是 Redisson 内部生成的一个唯一标识符,而64
是 Redis 分区信息。
"1":这是hash
字段的值,表示该分布式锁在 Redis 中处于锁定状态。Redis 使用字段的值来记录锁的状态,通常将其设置为1
表示锁定状态,当锁被释放时,字段的值会被删除或者设置为其他值。
如果在不知道"abc"类型的情况下,当做string来查询:
> get abc
(error) WRONGTYPE Operation against a key holding the wrong kind of value
在锁释放以后再来查询会得到:
> hgetall lock
(empty list or set)
可能的报错场景
1.字段使用冲突场景:
String lockKey = "abc"; //锁名称
String redisKey = "abc"; //redis的key
RLock rLock = redissonClient.getLock(lockKey);
try {
rLock.lock();
// 业务
} finally {
rLock.unlock();
}
报错可能是这样的:
ERR Error running script (call to f_3ffe249c16dee540ac8ab32e39bd408626b9aff7):
@user_script:1: WRONGTYPE Operation against a key holding the wrong kind of value .
channel: [id: 0x67a075d9, L:/127.0.0.1:14028 - R:localhost/127.0.0.1:6379]
command: (EVAL), promise: java.util.concurrent.CompletableFuture@5f77df46[Not completed],
params: [if (redis.call('hexists', KEYS[1], ARGV[3]) == 0) then return nil;end; local counter = redis.call('hincrby', KEYS[1], ARGV[3], -1);
if (counter > 0) then redis.call('pexpire', KEYS[1], ARGV[2]);
return 0; else redis.call('del', KEYS[1]); redis.call('publish', KEYS[2], ARGV[1]); return 1; end; return nil;,
2, lock, redisson_lock__channel:{lock}, 0, 30000, 76ffcf49-9bee-4fdc-a4bc-3ddaa918636b:64]
修改后不报错:
/**
两个不能一样
*/
String lockKey = "abc"; //锁名称
String redisKey = "abcd"; //redis的key
RLock rLock = redissonClient.getLock(lockKey);
try {
rLock.lock();
// 业务
} finally {
rLock.unlock();
}
原因就是redisson会在redis中存一个以"abc"为键的hash类型的值,如果abc已经存在,就会加锁不成功,类型也不匹配。实际业务中多会使用业务的id或者name来给redis或者redisson锁的名称来命名,还是要注意这一点。
2.业务没完成,锁已经过期?
try {
rLock.lock(5,TimeUnit.SECONDS);
//业务操作5秒,或者更多
}
} finally {
rLock.unlock();
}
会出现以下错误:
attempt to unlock lock, not locked by current thread by node id: a52a1561-66df-45d1-b4be-46c3319ca9b4 thread-id: 64
在 Redisson 中,锁的释放必须由持有锁的线程来完成。如果尝试由一个不是持有锁的线程来释放锁,就会出现上述错误。
如何解决:
//使用lock()
rLock.lock();
去掉过期时间的设置,只加锁,redisson会把过期时间设置为30秒,只要redisson还存在,就会每10秒续期一次。即倒计时30,29,...,21,续期到30秒,继续倒计时。
在程序故障时会等锁过期自动释放,或者业务完后unlock()也会释放锁。称为Watchdog,看门狗机制。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 无需6万激活码!GitHub神秘组织3小时极速复刻Manus,手把手教你使用OpenManus搭建本
· C#/.NET/.NET Core优秀项目和框架2025年2月简报
· Manus爆火,是硬核还是营销?
· 终于写完轮子一部分:tcp代理 了,记录一下
· 【杭电多校比赛记录】2025“钉耙编程”中国大学生算法设计春季联赛(1)