Redisson分布式鎖


Redisson分布式

GitHub中文文檔

概念:是一個在Redis的基礎上實現的Java駐內存數據網格(In-Memory Data Grid)。它不僅提供了一系列的分布式的Java常用對象,還提供了許多分布式服務

引入依賴

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

配置

@Configuration
public class MyRedissonConfig {

    @Bean(destroyMethod = "shutdown")
    public RedissonClient redissonClient() throws IOException{
        //1.配置連接
        Config config = new Config();
        config.useSingleServer()
                .setPassword("123456")
                //可以用"rediss://"來啟用SSL連接
                .setAddress("redis://123.56.16.54:6379");
        //2.創建客戶端
        RedissonClient redissonClient= Redisson.create(config);
        return redissonClient;
    }
}

分布式鎖

1、可重入鎖

@ResponseBody
    @GetMapping("/hello")
    public String hello() {

        //1、獲取一把鎖,只要鎖的名字一樣,就是同一把鎖
        RLock lock = redisson.getLock(" my-lock ");
        //2、加鎖
        lock.lock();//阻塞式等待。默認加的鎖都是30s時間。
        //1)、鎖的自動續期,如果業務超長,運行期間自動給鎖續上新的30s。不用擔心業務時間長,鎖自動過期被用特
        //2)、加鎖的業務只要運行完成,就不會給當前鎖續期,即使不手動解鎖,鎖默認在30s以后自動刪除。
        try{
            System.out.println("加鎖成功,執行業務..." + Thread.currentThread().getId());
            Thread.sleep(30000);
        } catch (Exception e) {

        } finally {
//3、解鎖將設解鎖代碼沒有運行,redisson會不會出現死鎖
            System.out.println("釋放鎖..." + Thread.currentThread().getId());
            lock.unlock();
        }
        return "hello";
    }

基於Redis的Redisson分布式可重入鎖RLock Java對象實現了java.util.concurrent.locks.Lock接口

大家都知道,如果負責儲存這個分布式鎖的Redisson節點宕機以后,而且這個鎖正好處於鎖住的狀態時,這個鎖會出現鎖死的狀態。為了避免這種情況的發生,Redisson內部提供了一個監控鎖的看門狗,它的作用是在Redisson實例被關閉前,不斷的延長鎖的有效期。默認情況下,看門狗的檢查鎖的超時時間是30秒鍾,也可以通過修改Config.lockWatchdogTimeout來另行指定。

try {
            while (true) {
                ttl = tryAcquire(leaseTime, unit, threadId);
                // lock acquired
                if (ttl == null) {
                    break;
                }

                // waiting for message
                if (ttl >= 0) {
                    try {
                        future.getNow().getLatch().tryAcquire(ttl, TimeUnit.MILLISECONDS);
                    } catch (InterruptedException e) {
                        if (interruptibly) {
                            throw e;
                        }
                        future.getNow().getLatch().tryAcquire(ttl, TimeUnit.MILLISECONDS);
                    }
                } else {
                    if (interruptibly) {
                        future.getNow().getLatch().acquire();
                    } else {
                        future.getNow().getLatch().acquireUninterruptibly();
                    }
                }
            }
        } finally {
            unsubscribe(future, threadId);
        }

另外Redisson還通過加鎖的方法提供了leaseTime的參數來指定加鎖的時間。超過這個時間后鎖便自動解開了。

// 加鎖以后10秒鍾自動解鎖,不會續期
// 無需調用unlock方法手動解鎖
lock.lock(10, TimeUnit.SECONDS);//10秒自動解鎖,自動解鎖時間一定要大於業務的執行時間。
//問題:Lock.Lock(10,TimeUnit.SECONDS);在鎖時間到了以后,不會自動續期。
//1、如果我們傳遞了鎖的超時時間,就發送給redis執行腳本,進行占鎖,默認超時就是我們指定的時間
//2、如果我們未指定鎖的超時時間,就使用30*1000(LockivatchdogTimeout看門狗的默認時間)
//只要占鎖成功,就會啟動一個定時任務(重新給看門狗定義過期時間,新的過期時間是默認的30s),每個10s自動續期到30s
// internalLockLeaseTime【看門狗時間】/3,10s后

// 嘗試加鎖,最多等待100秒,超出不等,上鎖以后10秒自動解鎖
boolean res = lock.tryLock(100, 10, TimeUnit.SECONDS);
if (res) {
   try {
     ...
   } finally {
       lock.unlock();
   }
}

2、公平鎖

保證了當多個Redisson客戶端線程同時請求加鎖時,優先分配給先發出請求的線程。所有請求線程會在一個隊列中排隊,當某個線程出現宕機時,Redisson會等待5秒后繼續下一個線程,也就是說如果前面有5個線程都處於等待狀態,那么后面的線程會等待至少25秒。

RLock fairLock = redisson.getFairLock("anyLock");
// 最常見的使用方法
fairLock.lock();

// 10秒鍾以后自動解鎖
// 無需調用unlock方法手動解鎖
fairLock.lock(10, TimeUnit.SECONDS);

// 嘗試加鎖,最多等待100秒,上鎖以后10秒自動解鎖
boolean res = fairLock.tryLock(100, 10, TimeUnit.SECONDS);
...
fairLock.unlock();

3、讀寫鎖

分布式可重入讀寫鎖允許同時有多個讀鎖和一個寫鎖處於加鎖狀態。

RReadWriteLock rwlock = redisson.getReadWriteLock("anyRWLock");
// 最常見的加鎖使用方法
rwlock.readLock().lock();
// 或
rwlock.writeLock().lock();


// 10秒鍾以后自動解鎖
// 無需調用unlock方法手動解鎖
rwlock.readLock().lock(10, TimeUnit.SECONDS);
// 或
rwlock.writeLock().lock(10, TimeUnit.SECONDS);

// 嘗試加鎖,最多等待100秒,上鎖以后10秒自動解鎖
boolean res = rwlock.readLock().tryLock(100, 10, TimeUnit.SECONDS);
// 或
boolean res = rwlock.writeLock().tryLock(100, 10, TimeUnit.SECONDS);
...
lock.unlock();

進行寫操作之前不能有鎖,進行讀操作之前可以有讀鎖,不能有寫鎖

4、信號量

	@ResponseBody
    @GetMapping("/acquire")
    public String AcquireSemaphore(){
        RSemaphore semaphore = redisson.getSemaphore("semaphore");
        //需要獲取幾個信號量參數就寫幾,默認為1
        boolean b = semaphore.tryAcquire();
        if(b){
            //獲取成功
            return "獲取成功:信號量-1..."+"當前信號量"+semaphore.availablePermits();
        }else{
            return "獲取失敗:等待...."+"當前信號量"+semaphore.availablePermits();
        }
    }

    @ResponseBody
    @GetMapping("/release")
    public String releaseSemaphore(){
        RSemaphore semaphore = redisson.getSemaphore("semaphore");
        semaphore.release();//semaphore.release(4);表示一次性釋放4個信號量
        return "釋放成功:信號量+1......"+"當前信號量"+semaphore.availablePermits();
    }

5、閉鎖

(CountDownLatch)

RCountDownLatch latch = redisson.getCountDownLatch("anyCountDownLatch");
latch.trySetCount(3);//redis中存在一個anyCountDownLatch=3,當其等於0時就閉鎖
latch.await();


// 在其他線程或其他JVM里
RCountDownLatch latch = redisson.getCountDownLatch("anyCountDownLatch");
latch.countDown();//redis中的anyCountDownLatch減一


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM