可重入鎖與不可重入鎖理解

梁哲發表於2024-06-26

測試可重入鎖

概念

  可重入鎖就是在一段程式碼(多執行緒呼叫也包括)中能夠重複獲取同一把鎖。例如:A和B兩個方法同時需要獲取同把鎖,在A方法獲取鎖後,B方法同樣可以獲取該鎖執行業務邏輯。

程式碼

    @Test
    void ReentrantLockTest() {
        long threadId = Thread.currentThread().getId();
        RLock lock = redissonClient.getLock("lock" + threadId);
        try {
            boolean isLockFirst = lock.tryLock(10000L, TimeUnit.SECONDS);
            System.out.println(isLockFirst ? "初次獲取鎖成功": "初次獲取鎖鎖失敗");
            boolean isLockSecond = lock.tryLock(10000L, TimeUnit.SECONDS);
            System.out.println(isLockSecond ? "再次獲取鎖成功": "再次獲取鎖鎖失敗");
        } catch (InterruptedException e) {
            log.error(String.valueOf(e));
        } finally {
            System.out.println("釋放鎖");
            lock.unlock();
        }

    }

執行結果

分析

  可以看出初次獲取鎖成功後,沒有等待鎖釋放,又一次成功獲取了鎖。這是因為Redisson利用hash結構記錄執行緒id和重入次數。

思考

  但是如果A、B兩個方法同時對資料表中的同一個資料進行修改時,會不會破壞資料一致性呢?

測試不可重入鎖

概念

  不可重入鎖就是在一段程式碼(多執行緒呼叫也包括)中不能夠重複獲取同一把鎖。例如:A和B兩個方法同時需要獲取同把鎖,在A方法獲取鎖後,B方法便不能獲取該鎖,只能被阻塞或執行失敗。

程式碼

    @Test
    void notReentrantLockTest() {
        long threadId = Thread.currentThread().getId();
        try {
            Boolean isLockFirst = stringRedisTemplate.opsForValue().setIfAbsent("lock" + threadId, "1", 1000, TimeUnit.SECONDS);
            System.out.println(Boolean.TRUE.equals(isLockFirst) ? "初次獲取鎖成功": "初次獲取鎖鎖失敗");
            Boolean isLockSecond = stringRedisTemplate.opsForValue().setIfAbsent("lock" + threadId, "1", 1000, TimeUnit.SECONDS);
            System.out.println(Boolean.TRUE.equals(isLockSecond) ? "再次獲取鎖成功": "再次獲取鎖鎖失敗");
        } catch (Exception e) {
            log.error(String.valueOf(e));
        } finally {
            System.out.println("釋放鎖");
            stringRedisTemplate.delete("lock" + threadId);
        }
    }

執行結果

分析

  可以看出初次獲取鎖成功後,再次獲取鎖失敗了,只能等待鎖被釋放後才能再次加鎖。

相關文章