這篇文章主要為大家分析了redis實(shí)現(xiàn)分布式重入鎖的方法是什么的相關(guān)知識(shí)點(diǎn),內(nèi)容詳細(xì)易懂,操作細(xì)節(jié)合理,具有一定參考價(jià)值。如果感興趣的話,不妨跟著跟隨小編一起來(lái)看看,下面跟著小編一起深入學(xué)習(xí)“redis實(shí)現(xiàn)分布式重入鎖的方法是什么”的知識(shí)吧。

創(chuàng)新互聯(lián)主要為客戶提供服務(wù)項(xiàng)目涵蓋了網(wǎng)頁(yè)視覺(jué)設(shè)計(jì)、VI標(biāo)志設(shè)計(jì)、營(yíng)銷(xiāo)網(wǎng)站、網(wǎng)站程序開(kāi)發(fā)、HTML5響應(yīng)式成都網(wǎng)站建設(shè)、成都做手機(jī)網(wǎng)站、微商城、網(wǎng)站托管及成都網(wǎng)站維護(hù)公司、WEB系統(tǒng)開(kāi)發(fā)、域名注冊(cè)、國(guó)內(nèi)外服務(wù)器租用、視頻、平面設(shè)計(jì)、SEO優(yōu)化排名。設(shè)計(jì)、前端、后端三個(gè)建站步驟的完善服務(wù)體系。一人跟蹤測(cè)試的建站服務(wù)標(biāo)準(zhǔn)。已經(jīng)為成都白烏魚(yú)行業(yè)客戶提供了網(wǎng)站營(yíng)銷(xiāo)服務(wù)。
即若當(dāng)前線程執(zhí)行某個(gè)方法已經(jīng)獲取了該鎖,那么在方法中嘗試再次獲取鎖時(shí),就會(huì)獲取不到而阻塞。
可重入鎖,也叫做遞歸鎖,指的是在同一線程內(nèi),外層函數(shù)獲得鎖之后,內(nèi)層遞歸函數(shù)仍然可以獲取到該鎖。 就是同一個(gè)線程再次進(jìn)入同樣代碼時(shí),可以再次拿到該鎖。
防止在同一線程中多次獲取鎖而導(dǎo)致死鎖發(fā)生。
注:在java的編程中synchronized 和 ReentrantLock都是可重入鎖。
步驟1:雙重加鎖邏輯
public class SynchronizedDemo {
//模擬庫(kù)存100
int count=100;
public synchronized void operation(){
log.info("第一層鎖:減庫(kù)存");
//模擬減庫(kù)存
count--;
add();
log.info("下訂單結(jié)束庫(kù)存剩余:{}",count);
}
private synchronized void add(){
log.info("第二層鎖:插入訂單");
try {
Thread.sleep(1000*10);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}步驟2:加個(gè)測(cè)試類(lèi)
public static void main(String[] args) {
SynchronizedDemo synchronizedDemo=new SynchronizedDemo();
for (int i = 0; i < 3; i++) {
int finalI = i;
new Thread(()->{
log.info("-------用戶{}開(kāi)始下單--------", finalI);
synchronizedDemo.operation();
}).start();
}
}步驟3:測(cè)試
20:44:04.013 [Thread-2] INFO com.agan.redis.controller.SynchronizedController - -------用戶2開(kāi)始下單-------- 20:44:04.013 [Thread-1] INFO com.agan.redis.controller.SynchronizedController - -------用戶1開(kāi)始下單-------- 20:44:04.013 [Thread-0] INFO com.agan.redis.controller.SynchronizedController - -------用戶0開(kāi)始下單-------- 20:44:04.016 [Thread-2] INFO com.agan.redis.Reentrant.SynchronizedDemo - 第一層鎖:減庫(kù)存 20:44:04.016 [Thread-2] INFO com.agan.redis.Reentrant.SynchronizedDemo - 第二層鎖:插入訂單 20:44:14.017 [Thread-2] INFO com.agan.redis.Reentrant.SynchronizedDemo - 下訂單結(jié)束庫(kù)存剩余:99 20:44:14.017 [Thread-0] INFO com.agan.redis.Reentrant.SynchronizedDemo - 第一層鎖:減庫(kù)存 20:44:14.017 [Thread-0] INFO com.agan.redis.Reentrant.SynchronizedDemo - 第二層鎖:插入訂單 20:44:24.017 [Thread-0] INFO com.agan.redis.Reentrant.SynchronizedDemo - 下訂單結(jié)束庫(kù)存剩余:98 20:44:24.017 [Thread-1] INFO com.agan.redis.Reentrant.SynchronizedDemo - 第一層鎖:減庫(kù)存 20:44:24.017 [Thread-1] INFO com.agan.redis.Reentrant.SynchronizedDemo - 第二層鎖:插入訂單 20:44:34.017 [Thread-1] INFO com.agan.redis.Reentrant.SynchronizedDemo - 下訂單結(jié)束庫(kù)存剩余:97
由于synchronized關(guān)鍵字修飾的是方法,所有加鎖為實(shí)例對(duì)象:synchronizedDemo
運(yùn)行結(jié)果可以看出減庫(kù)存和插入訂單都是每個(gè)線程都完整運(yùn)行兩個(gè)方法完畢,才能釋放鎖,其他線程才能拿鎖,即是一個(gè)線程多次可以拿到同一個(gè)鎖,可重入。所以synchronized也是可重入鎖。
ReentrantLock,是一個(gè)可重入且獨(dú)占式的鎖,是一種遞歸無(wú)阻塞的同步鎖。和synchronized關(guān)鍵字相比,它更靈活、更強(qiáng)大,增加了輪詢、超時(shí)、中斷等高級(jí)功能。
步驟1:雙重加鎖邏輯
public class ReentrantLockDemo {
private Lock lock = new ReentrantLock();
public void doSomething(int n){
try{
//進(jìn)入遞歸第一件事:加鎖
lock.lock();
log.info("--------遞歸{}次--------",n);
if(n<=2){
try {
Thread.sleep(1000*2);
} catch (InterruptedException e) {
e.printStackTrace();
}
this.doSomething(++n);
}else{
return;
}
}finally {
lock.unlock();
}
}
}步驟2:加個(gè)測(cè)試類(lèi)
public static void main(String[] args) {
ReentrantLockDemo reentrantLockDemo=new ReentrantLockDemo();
for (int i = 0; i < 3; i++) {
int finalI = i;
new Thread(()->{
log.info("-------用戶{}開(kāi)始下單--------", finalI);
reentrantLockDemo.doSomething(1);
}).start();
}
}步驟3:測(cè)試
20:55:23.533 [Thread-1] INFO com.agan.redis.controller.ReentrantController - -------用戶1開(kāi)始下單-------- 20:55:23.533 [Thread-2] INFO com.agan.redis.controller.ReentrantController - -------用戶2開(kāi)始下單-------- 20:55:23.533 [Thread-0] INFO com.agan.redis.controller.ReentrantController - -------用戶0開(kāi)始下單-------- 20:55:23.536 [Thread-1] INFO com.agan.redis.Reentrant.ReentrantLockDemo - --------遞歸1次-------- 20:55:25.537 [Thread-1] INFO com.agan.redis.Reentrant.ReentrantLockDemo - --------遞歸2次-------- 20:55:27.538 [Thread-1] INFO com.agan.redis.Reentrant.ReentrantLockDemo - --------遞歸3次-------- 20:55:27.538 [Thread-2] INFO com.agan.redis.Reentrant.ReentrantLockDemo - --------遞歸1次-------- 20:55:29.538 [Thread-2] INFO com.agan.redis.Reentrant.ReentrantLockDemo - --------遞歸2次-------- 20:55:31.539 [Thread-2] INFO com.agan.redis.Reentrant.ReentrantLockDemo - --------遞歸3次-------- 20:55:31.539 [Thread-0] INFO com.agan.redis.Reentrant.ReentrantLockDemo - --------遞歸1次-------- 20:55:33.539 [Thread-0] INFO com.agan.redis.Reentrant.ReentrantLockDemo - --------遞歸2次-------- 20:55:35.540 [Thread-0] INFO com.agan.redis.Reentrant.ReentrantLockDemo - --------遞歸3次--------
運(yùn)行結(jié)果可以看出,每個(gè)線程都可以多次加鎖解鎖的,ReentrantLock是可重入的。
setnx雖然可以實(shí)現(xiàn)分布式鎖,但是不可重入,在一些復(fù)雜的業(yè)務(wù)場(chǎng)景,我們需要分布式重入鎖時(shí),
對(duì)于redis的重入鎖業(yè)界還是有很多解決方案的,目前最流行的就是采用Redisson。【相關(guān)推薦:Redis視頻教程】
什么是Redisson?
Redisson是Redis官方推薦的Java版的Redis客戶端。
基于Java實(shí)用工具包中常用接口,為使用者提供了一系列具有分布式特性的常用工具類(lèi)。
在網(wǎng)絡(luò)通信上是基于NIO的Netty框架,保證網(wǎng)絡(luò)通信的高性能。
在分布式鎖的功能上,它提供了一系列的分布式鎖;如:
可重入鎖(Reentrant Lock)
公平鎖(Fair Lock)
非公平鎖(unFair Lock)
讀寫(xiě)鎖(ReadWriteLock)
聯(lián)鎖(MultiLock)
紅鎖(RedLock)
案例實(shí)戰(zhàn):體驗(yàn)redis分布式重入鎖
步驟1:Redisson配置
Redisson配置的可以查考:redis分布式緩存(三十四)一一 SpringBoot整合Redission - 掘金 (juejin.cn)
https://juejin.cn/post/7057132897819426824
步驟2:Redisson重入鎖測(cè)試類(lèi)
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:獲取一個(gè)分布式可重入鎖RLock
//分布式可重入鎖RLock :實(shí)現(xiàn)了java.util.concurrent.locks.Lock接口,同時(shí)還支持自動(dòng)過(guò)期解鎖。
RLock lock = redissonClient.getLock(key);
//步驟2:嘗試拿鎖
// 1. 默認(rèn)的拿鎖
//lock.tryLock();
// 2. 支持過(guò)期解鎖功能,10秒鐘以后過(guò)期自動(dòng)解鎖, 無(wú)需調(diào)用unlock方法手動(dòng)解鎖
//lock.tryLock(10, TimeUnit.SECONDS);
// 3. 嘗試加鎖,最多等待3秒,上鎖以后10秒后過(guò)期自動(dòng)解鎖
// lock.tryLock(3, 10, TimeUnit.SECONDS);
boolean bs = lock.tryLock(3, 10, TimeUnit.SECONDS);
if (bs) {
try {
// 業(yè)務(wù)代碼
log.info("線程{}業(yè)務(wù)邏輯處理: {},遞歸{}" ,Thread.currentThread().getName(), key,n);
//模擬處理業(yè)務(wù)
Thread.sleep(1000 * 5);
//模擬進(jìn)入遞歸
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());
}
}
}RLock三個(gè)加鎖動(dòng)作:
lock.tryLock();
默認(rèn)的拿鎖
lock.tryLock(10, TimeUnit.SECONDS);
支持過(guò)期解鎖功能,10秒鐘以后過(guò)期自動(dòng)解鎖
lock.tryLock(3, 10, TimeUnit.SECONDS);
嘗試加鎖,最多等待3秒,上鎖以后10秒后過(guò)期自動(dòng)解鎖
區(qū)別:
lock.lock():阻塞式等待。默認(rèn)加的鎖都是30s
鎖的自動(dòng)續(xù)期,如果業(yè)務(wù)超長(zhǎng),運(yùn)行期間自動(dòng)鎖上新的30s。不用擔(dān)心業(yè)務(wù)時(shí)間長(zhǎng)而導(dǎo)致鎖自動(dòng)過(guò)期被刪掉(默認(rèn)續(xù)期)
加鎖的業(yè)務(wù)只要運(yùn)行完成,就不會(huì)給當(dāng)前鎖續(xù)期,即使不手動(dòng)解鎖,鎖默認(rèn)會(huì)在30s內(nèi)自動(dòng)過(guò)期,不會(huì)產(chǎn)生死鎖問(wèn)題
lock()如果我們未指定鎖的超時(shí)時(shí)間,就使用【看門(mén)狗默認(rèn)時(shí)間】: lockWatchdogTimeout = 30 * 1000
原理:只要占鎖成功,就會(huì)啟動(dòng)一個(gè)定時(shí)任務(wù)【重新給鎖設(shè)置過(guò)期時(shí)間,新的過(guò)期時(shí)間就是看門(mén)狗的默認(rèn)時(shí)間】,每隔10秒都會(huì)自動(dòng)的再次續(xù)期,續(xù)成30秒
lock.lock(10,TimeUnit.SECONDS) :10秒鐘自動(dòng)解鎖,自動(dòng)解鎖時(shí)間一定要大于業(yè)務(wù)執(zhí)行時(shí)間
出現(xiàn)的問(wèn)題:在鎖時(shí)間到了以后,不會(huì)自動(dòng)續(xù)期
原理:lock(10,TimeUnit.SECONDS)如果我們傳遞了鎖的超時(shí)時(shí)間,就發(fā)送給redis執(zhí)行腳本,進(jìn)行占鎖,默認(rèn)超時(shí)就是我們制定的時(shí)間
最佳實(shí)戰(zhàn):
lock.lock(10,TimeUnit.SECONDS); 省掉看門(mén)狗續(xù)期操作,自動(dòng)解鎖時(shí)間一定要大于業(yè)務(wù)執(zhí)行時(shí)間,手動(dòng)解鎖
步驟3:測(cè)試
訪問(wèn)3次:http://127.0.0.1:9090/lock?key=ljw
線程http-nio-9090-exec-1業(yè)務(wù)邏輯處理: ljw,遞歸1 線程http-nio-9090-exec-2未取得鎖 線程http-nio-9090-exec-1業(yè)務(wù)邏輯處理: ljw,遞歸2 線程http-nio-9090-exec-3未取得鎖 線程http-nio-9090-exec-1業(yè)務(wù)邏輯處理: ljw,遞歸3 線程http-nio-9090-exec-1解鎖退出 線程http-nio-9090-exec-1解鎖退出 線程http-nio-9090-exec-1解鎖退出
通過(guò)測(cè)試結(jié)果:
nio-9090-exec-1線程,在getLock方法遞歸了3次,即證明了lock.tryLock是可重入鎖
只有當(dāng)nio-9090-exec-1線程執(zhí)行完后,io-9090-exec-2 nio-9090-exec-3 未取得鎖 因?yàn)閘ock.tryLock(3, 10, TimeUnit.SECONDS),嘗試加鎖,最多等待3秒,上鎖以后10秒后過(guò)期自動(dòng)解鎖 所以等了3秒都等不到,就放棄了
關(guān)于“redis實(shí)現(xiàn)分布式重入鎖的方法是什么”就介紹到這了,更多相關(guān)內(nèi)容可以搜索創(chuàng)新互聯(lián)以前的文章,希望能夠幫助大家答疑解惑,請(qǐng)多多支持創(chuàng)新互聯(lián)網(wǎng)站!
分享文章:redis實(shí)現(xiàn)分布式重入鎖的方法是什么
URL標(biāo)題:http://chinadenli.net/article22/ihpjcc.html
成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供靜態(tài)網(wǎng)站、營(yíng)銷(xiāo)型網(wǎng)站建設(shè)、定制網(wǎng)站、網(wǎng)站設(shè)計(jì)公司、微信小程序、域名注冊(cè)
聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請(qǐng)盡快告知,我們將會(huì)在第一時(shí)間刪除。文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如需處理請(qǐng)聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時(shí)需注明來(lái)源: 創(chuàng)新互聯(lián)