// 风格 1 (有隐患?)
RLock lock = redissonClient.getLock("lock:1666270081");
if (lock.tryLock()) {
try {
System.out.println("do in lock");
} finally {
lock.unlock();
}
}
// 风格 2
RLock lock = redissonClient.getLock("lock:1666270081");
try {
if (lock.tryLock()) {
System.out.println("do in lock");
}
} finally {
if (lock.isHeldByCurrentThread()) {
lock.unlock();
}
}
1
potatowish 2022-10-20 21:34:02 +08:00 via iPhone
这个 lock 如果被其他线程强制解锁再加锁,你这里 unlock 会抛异常
|
2
JinTianYi456 OP @potatowish #1 没懂,细说
|
3
Red998 2022-10-20 21:38:40 +08:00
建议这样
if (lock.isLocked() && lock.isHeldByCurrentThread()) { lock.unlock(); } |
4
JinTianYi456 OP @redorblacck886 #3 没必要吧
isLocked: `Checks if the lock locked by any thread` isHeldByCurrentThread: `Checks if this lock is held by the current thread` 所以只能 3 种情况吧, isLocked=true, isHeldByCurrentThread=true isLocked=true, isHeldByCurrentThread=false isLocked=false, isHeldByCurrentThread=false |
5
JinTianYi456 OP @potatowish #1 哦,你是说`风格 1`的,加锁了,然后我去敲命令删了那个 key ,然后 unlock 就报错了。忽略这种乱删 key 情况。主要是想比较 `风格 1`,先 lock ,然后进 try (这样有隐患吗)。`风格 2` 先 try ,再 lock 。
|
6
uselessVisitor 2022-10-20 22:12:21 +08:00
我一般是先 try ,稳一点
|
7
bthulu 2022-10-21 11:05:44 +08:00
风格 1 就行了
|
8
Chinsung 2022-10-21 11:47:32 +08:00
前排提示,如果不判断 lock.isHeldByCurrentThread()的话,unlock 会抛异常
起码我用的 redisson 版本是这样 |
9
JinTianYi456 OP @Chinsung #8 是指 5 楼里说到的情况?
|
10
vvtf 2022-10-21 17:33:15 +08:00
public final class RLockCloseable implements AutoCloseable {
private RLock lock; private boolean locked; public RLockCloseable(RLock lock) { Objects.nonNull(lock); this.lock = lock; } public static RLockCloseable of(RLock lock) { return new RLockCloseable(lock); } public static void ifLocked(RLock lock, Consumer<Void> fn) { try (RLockCloseable _lock = new RLockCloseable(lock)) { if (_lock.tryLock()) { fn.accept(null); } } } public boolean tryLock() { // or use isHeldByCurrentThread return locked = lock.tryLock(); } public void close() { if (locked) lock.unlock(); } } // usage //1. try (RLockCloseable lock = redisson.getLock("key")) { if (lock.tryLock()) { // TODO } } //2. RLockCloseable.ifLocked(redisson.getLock("key"), _t -> { // TODO }); |
11
Chinsung 2022-10-24 10:38:43 +08:00 1
@JinTianYi456 #9 并不是,而是第一个线程持有的锁如果因为执行时间过长超时,redis 锁的 key 失效了,第二个线程拿到了这个锁开始执行,此时第一个线程执行完了去释放锁的时候因为这个锁并不是他持有的,redisson 会抛异常,如果你写了事务,反而可能事务会因为这个异常回滚。
哪怕是不手动设置过期时间用看门狗也不一定能完全避免这种情况,因为看门狗底层还是给 key 设了过期时间的,只是看门狗能保证这种情况的概率会很低很低 |
12
JinTianYi456 OP @Chinsung #11 那我把`风格 1`的 unlock 也包上 isHeldByCurrentThread ,然后再比较`风格 1`,`风格 2`呢?
|
13
Chinsung 2022-10-25 14:51:43 +08:00
@JinTianYi456 #12 第二种,tryLock 可能有异常
|