通過優銳課核心java學習筆記中,我們可以看到,碼了很多專業的相關知識, 分享給大家參考學習。
了解有關分布式鎖定以及如何在項目中實作它的更多資訊!
什麼是分布式鎖定?
在多線程程式中,不同的線程可能需要通路相同的資源。但是,允許所有線程同時通路資源可能導緻争用情況,錯誤和其他意外行為。
為了確定沒有兩個線程可以同時通路同一資源,并確定以可預測的順序對資源進行操作,程式員使用一種稱為鎖的機制。每個線程首先擷取鎖,然後對資源進行操作,最後将鎖釋放給其他線程。
在Java中,由于多種原因,鎖定對象通常比使用同步塊更靈活。首先,Lock API可以以不同的方法運作,而同步塊完全包含在一個方法中。
另外,如果線程被阻止,則無法通路同步的塊。使用Lock,該線程将僅在可用時擷取鎖。這大大減少了線程等待的時間。另外,當線程正在等待時,可以調用一種方法來中斷線程,而當線程正在等待擷取同步塊時,這是不可能的。
分布式鎖定意味着你不僅需要考慮多個線程或程序,還需要考慮在不同計算機上運作的不同用戶端。這些單獨的伺服器必須進行協調,以確定它們中的任何一個在任何給定時間都在使用資源。
基于Redis的分布式Java鎖定工具Redisson架構是用于Java的基于Redis的記憶體資料網格,可為需要執行分布式鎖定的程式員提供多個對象。 下面,我們将讨論每個選項及其之間的差別。
1. 鎖RLock接口在Java中實作java.util.concurrent.locks.Lock接口。 這是一個可重入鎖,這意味着線程可以多次鎖定資源。 一個計數器變量跟蹤鎖定請求被執行了多少次。 一旦線程發出足夠的解鎖請求并且計數器達到0,資源便被釋放。
以下簡單代碼示例示範了如何在Redisson中建立和初始化Lock:
RLock lock = redisson.getLock("anyLock");
// Most familiar locking method
lock.lock();
try {
...
} finally {
lock.unlock();
}
如果擷取此鎖的Redisson執行個體崩潰,則該鎖可能會在此擷取狀态下永久挂起。 為了避免這種情況,Redisson維護了一個鎖“看門狗”,該“看門狗”會在持有該鎖的Redisson執行個體仍處于活動狀态時延長該鎖的過期時間。 預設情況下,此鎖定看門狗的逾時為30秒。 可以通過Config.lockWatchdogTimeout設定更改此限制。
Redisson還允許你在擷取租約時指定leaseTime參數。 在指定的時間間隔後,鎖将自動釋放:
// Acquire lock and release it automatically after 10 seconds
// if unlock method hasn't been invoked
lock.lock(10, TimeUnit.SECONDS);
// Wait for 100 seconds and automatically unlock it after 10 seconds
boolean res = lock.tryLock(100, 10, TimeUnit.SECONDS);
if (res) {
try {
...
} finally {
lock.unlock();
}
}
Redisson還為Lock對象提供了異步/響應/ rxjava2接口:
RLock lock = redisson.getLock("anyLock");
lock.lockAsync();
...
// Reactive Stream (Spring Project Reactor implementation)
RLockReactive lock = redissonReactive.getLock("anyLock");
Mono<Void> res = lock.lock();
...
// Reactive Stream (RxJava2 implementation)
RLockReactive lock = redissonRx.getLock("anyLock");
Flowable<Void> res = lock.lock();
...
由于RLock實作了Lock接口,是以隻有擁有鎖的線程才能解鎖資源。 否則,任何嘗試都會遇到IllegalMonitorStateException。
2. FairLock
與其表兄弟RLock一樣,RFairLock也實作了java.util.concurrent.locks.Lock接口。 通過使用FairLock,你可以保證線程将按照請求資源的順序來擷取資源(即``先進先出''隊列)。 在為隊列中的下一個線程解鎖資源之前,Redisson會給已死掉五秒鐘的線程重新啟動。
與RLocks一樣,建立和啟動FairLock是一個簡單的過程:
RLock lock = redisson.getFairLock("anyLock");
lock.lock();
try {
...
} catch {
lock.unlock();
}
3. ReadWriteLock
Redisson的RReadWriteLock實作了java.util.concurrent.locks.ReadWriteLock接口。 在Java中,讀/寫鎖實際上是兩個鎖的組合:一個隻讀鎖可以同時由多個線程擁有,而寫鎖隻能一次由一個線程擁有。
建立和初始化RReadWriteLock的方法如下:
RReadWriteLock rwlock = redisson.getReadWriteLock("anyRWLock");
rwlock.readLock().lock();
try {
...
} finally {
rwlock.readLock().lock();
}
rwlock.writeLock().lock();
try {
...
} finally {
rwlock.writeLock().lock();
}
4. RedLock
RedissonRedLock對象實作Redlock鎖定算法,以将分布式鎖與Redis一起使用:
RLock lock1 = redissonInstance1.getLock("lock1");
RLock lock2 = redissonInstance2.getLock("lock2");
RLock lock3 = redissonInstance3.getLock("lock3");
RedissonRedLock lock = new RedissonRedLock(lock1, lock2, lock3);
lock.lock();
try {
...
} finally {
lock.unlock();
}
在Redlock算法中,我們在單獨的計算機或虛拟機上有許多獨立的Redis主節點。 該算法嘗試使用相同的鍵名和随機值依次擷取這些執行個體中的每個執行個體的鎖。 僅當用戶端能夠比鎖有效的總時間更快地從大多數執行個體中擷取鎖時,才擷取鎖。
5.多重鎖
RedissonMultiLock對象能夠将多個單獨的RLock執行個體組合在一起并作為單個實體進行管理:
RLock lock1 = redissonInstance1.getLock("lock1");
RLock lock2 = redissonInstance2.getLock("lock2");
RLock lock3 = redissonInstance3.getLock("lock3");
RedissonMultiLock lock = new RedissonMultiLock(lock1, lock2, lock3);
lock.lock();
try {
...
} finally {
lock.unlock();
}
正如我們在上面的示例中看到的那樣,每個RLock對象可能屬于不同的Redisson執行個體。 反過來,這可能會連接配接到其他Redis資料庫。
最後的想法
在本文中,我們探讨了Java開發人員可用于在Redis資料庫之上的Redisson架構中執行分布式鎖定的一些不同工具:Lock,FairLock,ReadWriteLock,RedLock和MultiLock。 有關Redisson中分布式計算的更多資訊,請遵循GitHub上的項目Wiki。
> 喜歡這篇文章的可以點個贊,歡迎大家留言評論,記得關注我,每天持續更新技術幹貨、職場趣事、海量面試資料等等
> 如果你對java技術很感興趣也可以交流學習,共同學習進步。
> 不要再用"沒有時間“來掩飾自己思想上的懶惰!趁年輕,使勁拼,給未來的自己一個交代
文章寫道這裡,歡迎完善交流。最後奉上近期整理出來的一套完整的java架構思維導圖,分享給大家對照知識點參考學習。有更多JVM、Mysql、Tomcat、Spring Boot、Spring Cloud、Zookeeper、Kafka、RabbitMQ、RockerMQ、Redis、ELK、Git等Java幹貨
![](https://img.laitimes.com/img/__Qf2AjLwojIjJCLyojI0JCLicmbw5SOwImYxUGZmZWY4MzM1ImNiJzNiJWO0ETN2ADNyUWY28CX0JXZ252bj91Ztl2Lc52YucWbp5GZzNmLn9Gbi1yZtl2Lc9CX6MHc0RHaiojIsJye.png)