V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
JinTianYi456
V2EX  ›  Java

RedissonClient, 这种 lock 风格有隐患吗?

  •  
  •   JinTianYi456 · 2022-10-20 21:30:24 +08:00 · 1979 次点击
    这是一个创建于 525 天前的主题,其中的信息可能已经有所发展或是发生改变。
    // 风格 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();
        }
    }
    
    13 条回复    2022-10-25 14:51:43 +08:00
    potatowish
        1
    potatowish  
       2022-10-20 21:34:02 +08:00 via iPhone
    这个 lock 如果被其他线程强制解锁再加锁,你这里 unlock 会抛异常
    JinTianYi456
        2
    JinTianYi456  
    OP
       2022-10-20 21:37:12 +08:00
    @potatowish #1 没懂,细说
    Red998
        3
    Red998  
       2022-10-20 21:38:40 +08:00
    建议这样
    if (lock.isLocked() && lock.isHeldByCurrentThread()) {
    lock.unlock();
    }
    JinTianYi456
        4
    JinTianYi456  
    OP
       2022-10-20 21:49:09 +08:00
    @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
    JinTianYi456
        5
    JinTianYi456  
    OP
       2022-10-20 21:53:58 +08:00
    @potatowish #1 哦,你是说`风格 1`的,加锁了,然后我去敲命令删了那个 key ,然后 unlock 就报错了。忽略这种乱删 key 情况。主要是想比较 `风格 1`,先 lock ,然后进 try (这样有隐患吗)。`风格 2` 先 try ,再 lock 。
    uselessVisitor
        6
    uselessVisitor  
       2022-10-20 22:12:21 +08:00
    我一般是先 try ,稳一点
    bthulu
        7
    bthulu  
       2022-10-21 11:05:44 +08:00
    风格 1 就行了
    Chinsung
        8
    Chinsung  
       2022-10-21 11:47:32 +08:00
    前排提示,如果不判断 lock.isHeldByCurrentThread()的话,unlock 会抛异常
    起码我用的 redisson 版本是这样
    JinTianYi456
        9
    JinTianYi456  
    OP
       2022-10-21 14:09:18 +08:00
    @Chinsung #8 是指 5 楼里说到的情况?
    vvtf
        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
    });
    Chinsung
        11
    Chinsung  
       2022-10-24 10:38:43 +08:00   ❤️ 1
    @JinTianYi456 #9 并不是,而是第一个线程持有的锁如果因为执行时间过长超时,redis 锁的 key 失效了,第二个线程拿到了这个锁开始执行,此时第一个线程执行完了去释放锁的时候因为这个锁并不是他持有的,redisson 会抛异常,如果你写了事务,反而可能事务会因为这个异常回滚。
    哪怕是不手动设置过期时间用看门狗也不一定能完全避免这种情况,因为看门狗底层还是给 key 设了过期时间的,只是看门狗能保证这种情况的概率会很低很低
    JinTianYi456
        12
    JinTianYi456  
    OP
       2022-10-24 13:22:32 +08:00
    @Chinsung #11 那我把`风格 1`的 unlock 也包上 isHeldByCurrentThread ,然后再比较`风格 1`,`风格 2`呢?
    Chinsung
        13
    Chinsung  
       2022-10-25 14:51:43 +08:00
    @JinTianYi456 #12 第二种,tryLock 可能有异常
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   我们的愿景   ·   实用小工具   ·   5836 人在线   最高记录 6543   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 28ms · UTC 06:19 · PVG 14:19 · LAX 23:19 · JFK 02:19
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.