Redisson分散式鎖
來自Githup官方文件的介紹:
Redisson是一個在Redis的基礎上實現的Java駐記憶體資料網格(In-Memory Data Grid)。它不僅提供了一系列的分散式的Java常用物件,還提供了許多分散式服務。其中包括(BitSet
, Set
, Multimap
, SortedSet
, Map
, List
, Queue
, BlockingQueue
, Deque
, BlockingDeque
, Semaphore
, Lock
, AtomicLong
, CountDownLatch
, Publish / Subscribe
, Bloom filter
, Remote service
, Spring cache
, Executor service
, Live Object service
, Scheduler service
) Redisson提供了使用Redis的最簡單和最便捷的方法。Redisson的宗旨是促進使用者對Redis的關注分離(Separation of Concern),從而讓使用者能夠將精力更集中地放在處理業務邏輯上。
官方文件地址:https://github.com/redisson/redisson/wiki
中文文件地址:https://github.com/redisson/redisson/wiki/目錄
先講一下為什麼使用分散式鎖:
在傳統的單體應用中,我們可以使用Java併發處理相關的API(如ReentrantLock或synchronized)來實現對共享資源的互斥控制,確保在高併發情況下同一時間只有一個執行緒能夠執行特定方法。然而,隨著業務的發展,單體應用逐漸演化為分散式系統,多執行緒、多程序分佈在不同機器上,這導致了原有的單機部署下的併發控制策略失效。為了解決這一問題,我們需要引入一種跨JVM的互斥機制來管理共享資源的訪問,這就是分散式鎖所要解決的核心問題。
SpringBoot框架整合
1.引入依賴
<dependency>
<groupId>org.redisson</groupId>
<artifactId>redisson-spring-boot-starter</artifactId>
<version>3.15.5</version>
</dependency>
2.建立配置類
@Configuration
public class RedissonConfig {
@Value("${spring.redis.host}")
private String redisHost;
@Value("${spring.redis.port}")
private int redisPort;
@Value("${spring.redis.password}")
private String password;
@Value("${spring.redis.database}")
private int database;
@Bean
public RedissonClient redissonClient() {
Config config = new Config();
config.useSingleServer()
.setAddress("redis://" + redisHost + ":" + redisPort)
.setPassword(password)
.setDatabase(database)
.setConnectionMinimumIdleSize(10) // 連線池最小空閒連線數
.setConnectionPoolSize(50) // 連線池最大連線數
.setIdleConnectionTimeout(60000) // 執行緒超時時間
.setConnectTimeout(60000) // 客戶端程式獲取redis連線超時時間
.setTimeout(60000); // 響應超時時間
return Redisson.create(config);
}
}
叢集的配置參考:https://github.com/redisson/redisson/wiki/2.-配置方法#24-叢集模式
3.實際使用
public void checkAndLock5() {
RLock redisson_lock = redissonClient.getLock("redisson_lock");
try{
redisson_lock.lock();
// 1. 業務程式碼
}finally {
redisson_lock.unlock();
}
}
可重入鎖(Reentrant Lock)
基於Redis的Redisson分散式可重入鎖RLock
Java物件實現了java.util.concurrent.locks.Lock
介面。同時還提供了非同步(Async)、反射式(Reactive)和RxJava2標準的介面
RLock lock = redisson.getLock("anyLock");
// 最常見的使用方法
lock.lock();
大家都知道,如果負責儲存這個分散式鎖的Redisson節點當機以後,而且這個鎖正好處於鎖住的狀態時,這個鎖會出現鎖死的狀態。為了避免這種情況的發生,Redisson內部提供了一個監控鎖的看門狗,它的作用是在Redisson例項被關閉前,不斷的延長鎖的有效期。預設情況下,看門狗的檢查鎖的超時時間是30秒鐘,也可以透過修改Config.lockWatchdogTimeout來另行指定。
另外Redisson還透過加鎖的方法提供了leaseTime
的引數來指定加鎖的時間。超過這個時間後鎖便自動解開了。
// 加鎖以後10秒鐘自動解鎖
// 無需呼叫unlock方法手動解鎖
lock.lock(10, TimeUnit.SECONDS);
// 嘗試加鎖,最多等待100秒,上鎖以後10秒自動解鎖
boolean res = lock.tryLock(100, 10, TimeUnit.SECONDS);
if (res) {
try {
...
} finally {
lock.unlock();
}
}
公平鎖(Fair Lock)
基於Redis的Redisson分散式可重入公平鎖也是實現了java.util.concurrent.locks.Lock
介面的一種RLock
物件。同時還提供了非同步(Async)、反射式(Reactive)和RxJava2標準的介面。它保證了當多個Redisson客戶端執行緒同時請求加鎖時,優先分配給先發出請求的執行緒。所有請求執行緒會在一個佇列中排隊,當某個執行緒出現當機時,Redisson會等待5秒後繼續下一個執行緒,也就是說如果前面有5個執行緒都處於等待狀態,那麼後面的執行緒會等待至少25秒。
RLock fairLock = redisson.getFairLock("anyLock");
// 最常見的使用方法
fairLock.lock();
大家都知道,如果負責儲存這個分散式鎖的Redis節點當機以後,而且這個鎖正好處於鎖住的狀態時,這個鎖會出現鎖死的狀態。為了避免這種情況的發生,Redisson內部提供了一個監控鎖的看門狗,它的作用是在Redisson例項被關閉前,不斷的延長鎖的有效期。預設情況下,看門狗的檢查鎖的超時時間是30秒鐘,也可以透過修改Config.lockWatchdogTimeout來另行指定。
另外Redisson還透過加鎖的方法提供了leaseTime
的引數來指定加鎖的時間。超過這個時間後鎖便自動解開了。
// 10秒鐘以後自動解鎖
// 無需呼叫unlock方法手動解鎖
fairLock.lock(10, TimeUnit.SECONDS);
// 嘗試加鎖,最多等待100秒,上鎖以後10秒自動解鎖
boolean res = fairLock.tryLock(100, 10, TimeUnit.SECONDS);
...
fairLock.unlock();
聯鎖(MultiLock)
基於Redis的Redisson分散式聯鎖RedissonMultiLock
物件可以將多個RLock
物件關聯為一個聯鎖,每個RLock
物件例項可以來自於不同的Redisson例項。
RLock lock1 = redissonInstance1.getLock("lock1");
RLock lock2 = redissonInstance2.getLock("lock2");
RLock lock3 = redissonInstance3.getLock("lock3");
RedissonMultiLock lock = new RedissonMultiLock(lock1, lock2, lock3);
// 同時加鎖:lock1 lock2 lock3
// 所有的鎖都上鎖成功才算成功。
lock.lock();
...
lock.unlock();
大家都知道,如果負責儲存某些分散式鎖的某些Redis節點當機以後,而且這些鎖正好處於鎖住的狀態時,這些鎖會出現鎖死的狀態。為了避免這種情況的發生,Redisson內部提供了一個監控鎖的看門狗,它的作用是在Redisson例項被關閉前,不斷的延長鎖的有效期。預設情況下,看門狗的檢查鎖的超時時間是30秒鐘,也可以透過修改Config.lockWatchdogTimeout來另行指定。
另外Redisson還透過加鎖的方法提供了leaseTime
的引數來指定加鎖的時間。超過這個時間後鎖便自動解開了。
RedissonMultiLock lock = new RedissonMultiLock(lock1, lock2, lock3);
// 給lock1,lock2,lock3加鎖,如果沒有手動解開的話,10秒鐘後將會自動解開
lock.lock(10, TimeUnit.SECONDS);
// 為加鎖等待100秒時間,並在加鎖成功10秒鐘後自動解開
boolean res = lock.tryLock(100, 10, TimeUnit.SECONDS);
...
lock.unlock();
紅鎖(RedLock)
基於Redis的Redisson紅鎖RedissonRedLock
物件實現了Redlock介紹的加鎖演算法。該物件也可以用來將多個RLock
物件關聯為一個紅鎖,每個RLock
物件例項可以來自於不同的Redisson例項。
RLock lock1 = redissonInstance1.getLock("lock1");
RLock lock2 = redissonInstance2.getLock("lock2");
RLock lock3 = redissonInstance3.getLock("lock3");
RedissonRedLock lock = new RedissonRedLock(lock1, lock2, lock3);
// 同時加鎖:lock1 lock2 lock3
// 紅鎖在大部分節點上加鎖成功就算成功。
lock.lock();
...
lock.unlock();
大家都知道,如果負責儲存某些分散式鎖的某些Redis節點當機以後,而且這些鎖正好處於鎖住的狀態時,這些鎖會出現鎖死的狀態。為了避免這種情況的發生,Redisson內部提供了一個監控鎖的看門狗,它的作用是在Redisson例項被關閉前,不斷的延長鎖的有效期。預設情況下,看門狗的檢查鎖的超時時間是30秒鐘,也可以透過修改Config.lockWatchdogTimeout來另行指定。
另外Redisson還透過加鎖的方法提供了leaseTime
的引數來指定加鎖的時間。超過這個時間後鎖便自動解開了。
RedissonRedLock lock = new RedissonRedLock(lock1, lock2, lock3);
// 給lock1,lock2,lock3加鎖,如果沒有手動解開的話,10秒鐘後將會自動解開
lock.lock(10, TimeUnit.SECONDS);
// 為加鎖等待100秒時間,並在加鎖成功10秒鐘後自動解開
boolean res = lock.tryLock(100, 10, TimeUnit.SECONDS);
...
lock.unlock();
讀寫鎖(ReadWriteLock)
基於Redis的Redisson分散式可重入讀寫鎖RReadWriteLock
Java物件實現了java.util.concurrent.locks.ReadWriteLock
介面。其中讀鎖和寫鎖都繼承了RLock介面。
分散式可重入讀寫鎖允許同時有多個讀鎖和一個寫鎖處於加鎖狀態。
RReadWriteLock rwlock = redisson.getReadWriteLock("anyRWLock");
// 最常見的使用方法
rwlock.readLock().lock();
// 或
rwlock.writeLock().lock();
大家都知道,如果負責儲存這個分散式鎖的Redis節點當機以後,而且這個鎖正好處於鎖住的狀態時,這個鎖會出現鎖死的狀態。為了避免這種情況的發生,Redisson內部提供了一個監控鎖的看門狗,它的作用是在Redisson例項被關閉前,不斷的延長鎖的有效期。預設情況下,看門狗的檢查鎖的超時時間是30秒鐘,也可以透過修改Config.lockWatchdogTimeout來另行指定。
另外Redisson還透過加鎖的方法提供了leaseTime
的引數來指定加鎖的時間。超過這個時間後鎖便自動解開了。
// 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();
訊號量(Semaphore)
基於Redis的Redisson的分散式訊號量(Semaphore)Java物件RSemaphore
採用了與java.util.concurrent.Semaphore
相似的介面和用法。同時還提供了非同步(Async)、反射式(Reactive)和RxJava2標準的介面。
RSemaphore semaphore = redisson.getSemaphore("semaphore");
semaphore.acquire();
//或
semaphore.acquireAsync();
semaphore.acquire(23);
semaphore.tryAcquire();
//或
semaphore.tryAcquireAsync();
semaphore.tryAcquire(23, TimeUnit.SECONDS);
//或
semaphore.tryAcquireAsync(23, TimeUnit.SECONDS);
semaphore.release(10);
semaphore.release();
//或
semaphore.releaseAsync();
閉鎖(CountDownLatch)
基於Redisson的Redisson分散式閉鎖(CountDownLatch)Java物件RCountDownLatch
採用了與java.util.concurrent.CountDownLatch
相似的介面和用法。
RCountDownLatch latch = redisson.getCountDownLatch("anyCountDownLatch");
latch.trySetCount(1);
latch.await();
// 在其他執行緒或其他JVM裡
RCountDownLatch latch = redisson.getCountDownLatch("anyCountDownLatch");
latch.countDown();