redis如何實現分佈式重入鎖

redis如何實現分佈式重入鎖?

在上一節課中,我們已經知道SETNX是不支持重入鎖的,但我們需要重入鎖,怎麼辦呢?
目前對於redis的重入鎖業界還是有很多解決方案的,最流行的就是採用Redisson,關於什麼是Redisson?下面詳細介紹

什麼是 Redisson?

Redisson是Redis官方推薦的Java版的Redis客戶端。
它基於Java實用工具包中常用接口,爲使用者提供了一系列具有分佈式特性的常用工具類。
它在網絡通信上是基於NIO的Netty框架,保證網絡通信的高性能。
在分佈式鎖的功能上,它提供了一系列的分佈式鎖;如:可重入鎖(Reentrant Lock)、公平鎖(Fair Lock、聯鎖(MultiLock)、
紅鎖(RedLock)、 讀寫鎖(ReadWriteLock)等等。

案例實戰:體驗redis分佈式重入鎖

步驟1:加入pom依賴包

<dependency>
    <groupId>org.redisson</groupId>
    <artifactId>redisson</artifactId>
    <version>3.9.0</version>
</dependency>

步驟2:配置文件

#redi開關配置 見:封裝類 CacheConfiguration
#設置模式 sentinel/cluster/single
spring.redis.mode=single

#redis基礎配置 見:封裝類 RedisProperties
spring.redis.database=0
spring.redis.password=
spring.redis.timeout=3000

#redis線程池配置  見:封裝類 RedisPoolProperties
spring.redis.pool.conn-timeout=3000
spring.redis.pool.so-timeout=3000
spring.redis.pool.size=10

#單機模式 見:封裝類 RedisSingleProperties
spring.redis.single.address=192.168.1.138:6379

#集羣模式 見:封裝類 RedisClusterProperties
spring.redis.cluster.scan-interval=1000
spring.redis.cluster.nodes=192.168.2.58:7000,192.168.2.58:7001,192.168.2.58:7002,192.168.2.58:7003,192.168.2.58:7004,192.168.2.58:7005,192.168.2.58:7006
spring.redis.cluster.read-mode=SLAVE
spring.redis.cluster.retry-attempts=3
spring.redis.cluster.failed-attempts=3
spring.redis.cluster.slave-connection-pool-size=64
spring.redis.cluster.master-connection-pool-size=64
spring.redis.cluster.retry-interval=1500

#哨兵模式 見:RedisSentinelProperties
spring.redis.sentinel.master=business-master
spring.redis.sentinel.nodes=
spring.redis.sentinel.master-onlyWrite=true
spring.redis.sentinel.fail-max=3

步驟3:Redisson重入鎖代碼

public class RedisController {

    @Autowired
    RedissonClient redissonClient;

    @GetMapping(value = "/lock")
    public void get(String key) throws InterruptedException {
        this.getLock(key, 1);
    }

    private void getLock(String key, int n) throws InterruptedException {
        //模擬遞歸,3次遞歸後退出
        if (n > 3) {
            return;
        }
        //步驟1:獲取一個分佈式可重入鎖RLock
        //分佈式可重入鎖RLock :實現了java.util.concurrent.locks.Lock接口,同時還支持自動過期解鎖。
        RLock lock = redissonClient.getLock(key);
        //步驟2:嘗試拿鎖
        // 1. 默認的拿鎖
        //lock.tryLock();
        // 2. 支持過期解鎖功能,10秒鐘以後過期自動解鎖, 無需調用unlock方法手動解鎖
        //lock.tryLock(10, TimeUnit.SECONDS);
        // 3. 嘗試加鎖,最多等待3秒,上鎖以後10秒後過期自動解鎖
        // lock.tryLock(3, 10, TimeUnit.SECONDS);
        boolean bs = lock.tryLock(3, 10, TimeUnit.SECONDS);
        if (bs) {
            try {
                // 業務代碼
                log.info("線程{}業務邏輯處理: {},遞歸{}" ,Thread.currentThread().getName(), key,n);
                //模擬處理業務
                Thread.sleep(1000 * 5);
                //模擬進入遞歸
                this.getLock(key, ++n);
            } catch (Exception e) {
                log.error(e.getLocalizedMessage());
            } finally {
                //步驟3:解鎖
                lock.unlock();
                log.info("線程{}解鎖退出",Thread.currentThread().getName());
            }
        } else {
            log.info("線程{}未取得鎖",Thread.currentThread().getName());
        }
    }
}

步驟4:體驗測試

ie流浪器輸入:http://192.168.1.4:9090/lock?key=aganlock
刷新3次 看效果

2020-03-08 12:19:24.237  INFO 76507 --- [nio-9090-exec-1] c.agan.redis.controller.RedisController  : 線程http-nio-9090-exec-1業務邏輯處理: aganlock,遞歸1
2020-03-08 12:19:29.069  INFO 76507 --- [nio-9090-exec-2] c.agan.redis.controller.RedisController  : 線程http-nio-9090-exec-2未取得鎖
2020-03-08 12:19:29.377  INFO 76507 --- [nio-9090-exec-1] c.agan.redis.controller.RedisController  : 線程http-nio-9090-exec-1業務邏輯處理: aganlock,遞歸2
2020-03-08 12:19:31.896  INFO 76507 --- [nio-9090-exec-3] c.agan.redis.controller.RedisController  : 線程http-nio-9090-exec-3未取得鎖
2020-03-08 12:19:34.579  INFO 76507 --- [nio-9090-exec-1] c.agan.redis.controller.RedisController  : 線程http-nio-9090-exec-1業務邏輯處理: aganlock,遞歸3
2020-03-08 12:19:39.820  INFO 76507 --- [nio-9090-exec-1] c.agan.redis.controller.RedisController  : 線程http-nio-9090-exec-1解鎖退出
2020-03-08 12:19:39.823  INFO 76507 --- [nio-9090-exec-1] c.agan.redis.controller.RedisController  : 線程http-nio-9090-exec-1解鎖退出
2020-03-08 12:19:39.827  INFO 76507 --- [nio-9090-exec-1] c.agan.redis.controller.RedisController  : 線程http-nio-9090-exec-1解鎖退出

通過測試結果:
1.發送了3次請求,springboot啓用了3條線程來處理,分別是nio-9090-exec-1 io-9090-exec-2 nio-9090-exec-3
2.nio-9090-exec-1線程,在getLock方法遞歸了3次,即證明了lock.tryLock是可重入鎖
3.只有當nio-9090-exec-1線程執行完後,io-9090-exec-2 nio-9090-exec-3 未取得鎖
因爲lock.tryLock(3, 10, TimeUnit.SECONDS),嘗試加鎖,最多等待3秒,上鎖以後10秒後過期自動解鎖
所以等了3秒都等不到,就放棄了

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章