摘要:分布式鎖基于實(shí)現(xiàn)分布式鎖思考幾個(gè)問(wèn)題鎖為什么不能應(yīng)用于分布式鎖雖然能夠解決同步問(wèn)題,但是每次只有一個(gè)線(xiàn)程訪(fǎng)問(wèn),并且鎖屬于鎖,僅適用于單點(diǎn)部署然而分布式需要部署多臺(tái)實(shí)例,屬于不同的線(xiàn)程對(duì)象使用中實(shí)現(xiàn)分布式鎖。
分布式鎖
基于redis實(shí)現(xiàn)分布式鎖思考幾個(gè)問(wèn)題?
synchronized鎖為什么不能應(yīng)用于分布式鎖?
synchronized雖然能夠解決同步問(wèn)題,但是每次只有一個(gè)線(xiàn)程訪(fǎng)問(wèn),并且synchronized鎖屬于JVM鎖,僅適用于單點(diǎn)部署;然而分布式需要部署多臺(tái)實(shí)例,屬于不同的JVM線(xiàn)程對(duì)象
使用redis中setnx實(shí)現(xiàn)分布式鎖。
//設(shè)置分布式鎖
String lockKey = "product_001_key";
//語(yǔ)義:如何不存在則存入緩存中,且返回true;
//否則已存在,則返回false即加鎖失敗
Boolean result = stringRedisTemplate.opsForValue().setIfAbsent(lockKey, "product_001_lock");
if (!result) {
//沒(méi)有加鎖成功,則返回提示等
}
try{
}catch() {
}finally{
//釋放鎖
stringRedisTemplate.delete(lockKey);
}
針對(duì)以上設(shè)置分布式鎖思考一下問(wèn)題?
1.如果突然服務(wù)器宕機(jī),那么必然造成鎖無(wú)法釋放,即造成死鎖?
解決方案:設(shè)置超時(shí)時(shí)間。
//設(shè)置分布式鎖
String lockKey = "product_001_key";
Boolean result = stringRedisTemplate.opsForValue().setIfAbsent(lockKey, "product_001_lock");
//設(shè)置鎖超時(shí)時(shí)間30s
stringRedisTemplate.expire(lockKey,30, TimeUnit.SECONDS);
if (!result) {
//沒(méi)有加鎖成功,則返回提示等
}
try{
}catch() {
}finally{
//釋放鎖
stringRedisTemplate.delete(lockKey);
}
2.加鎖和設(shè)置超時(shí)時(shí)間中間引起服務(wù)器宕機(jī),則一樣會(huì)導(dǎo)致死鎖。
Boolean result = stringRedisTemplate.opsForValue().setIfAbsent(lockKey, "product_001_lock");
//------服務(wù)器宕機(jī),則超時(shí)時(shí)間未設(shè)置成功-------
//設(shè)置鎖超時(shí)時(shí)間30s
stringRedisTemplate.expire(lockKey,30, TimeUnit.SECONDS);
解決方案:原子性操作,即同時(shí)加鎖和設(shè)置超時(shí)時(shí)間;
即上面的代碼合并成一句操作:
Boolean result = stringRedisTemplate.opsForValue().setIfAbsent(lockKey,"product_001_lock", 30, TimeUnit.SECONDS)
3.思考超時(shí)時(shí)間設(shè)置是否合理呢?即線(xiàn)程執(zhí)行時(shí)間和鎖超時(shí)時(shí)間并非一致。
場(chǎng)景:假設(shè)設(shè)置加鎖超時(shí)時(shí)間10s;
高并發(fā)場(chǎng)景下,線(xiàn)程A執(zhí)行時(shí)間為15s,redis依據(jù)超時(shí)時(shí)間,將其線(xiàn)程A加的鎖釋放掉;然后線(xiàn)程B獲取鎖,并加鎖成功,此時(shí)線(xiàn)程A執(zhí)行結(jié)束,執(zhí)行finally代碼塊就會(huì)將線(xiàn)程B加的鎖釋放。
解決方案:設(shè)置線(xiàn)程隨機(jī)ID,釋放鎖時(shí)判斷是否為當(dāng)前線(xiàn)程加的鎖,即使存在線(xiàn)程A因線(xiàn)程執(zhí)行時(shí)間超時(shí)被動(dòng)釋放其鎖,但至少保證當(dāng)前超時(shí)線(xiàn)程不會(huì)釋放其他線(xiàn)程加的鎖。但是面對(duì)線(xiàn)程執(zhí)行時(shí)間大于設(shè)置的超時(shí)時(shí)間,也是會(huì)存在并發(fā)問(wèn)題。
String lockKey = "product_001";
String clientId = UUID.randomUUID().toString();
//設(shè)置超時(shí)時(shí)間,且加鎖和設(shè)置線(xiàn)程ID
Boolean result = stringRedisTemplate.opsForValue().setIfAbsent(lockKey,clientId, 30, TimeUnit.SECONDS)`
if (!result) {
//沒(méi)有加鎖成功,則返回提示等
}
try{
}catch() {
}finally{
//釋放鎖:加鎖線(xiàn)程ID和當(dāng)前執(zhí)行線(xiàn)程ID相同,才允許釋放鎖
if (clientId.equals(stringRedisTemplate.opsForValue().get(lockKey))){
stringRedisTemplate.delete(lockKey);
}
}
4.上面場(chǎng)景解決方案:加鎖續(xù)命即續(xù)線(xiàn)程鎖超時(shí)時(shí)間
解決方案:加鎖成功時(shí),開(kāi)啟一個(gè)后臺(tái)線(xiàn)程,每隔10s(自定義)判斷當(dāng)前線(xiàn)程是否還持有鎖,持有鎖則再續(xù)命30s等
Redission實(shí)現(xiàn)分布式鎖
實(shí)現(xiàn)原理流程:
String lockKey = "product_001";
//獲取鎖對(duì)象,并未加鎖
RLock redissonLock = redisson.getLock(lockKey);
try {
// **此時(shí)加鎖**,實(shí)現(xiàn)鎖續(xù)命功能
redissonLock.lock();
int stock = Integer.parseInt(stringRedisTemplate.opsForValue().get("stock"));
if (stock > 0) {
int realStock = stock - 1;
stringRedisTemplate.opsForValue().set("stock", realStock + "");
System.out.println("扣減成功,剩余庫(kù)存:" + realStock + "");
} else {
System.out.println("扣減失敗,庫(kù)存不足");
}
}finally {
//釋放鎖
redissonLock.unlock();
}
總結(jié)
綜上,設(shè)計(jì)實(shí)現(xiàn)分布式鎖需要滿(mǎn)足一下條件:
1.互斥性;在任意時(shí)刻,只有一個(gè)客戶(hù)端能持有鎖。
2.不能發(fā)生死鎖;即使存在一個(gè)線(xiàn)程持有鎖的期間崩潰而沒(méi)有主動(dòng)解鎖,也能保證后續(xù)其他線(xiàn)程能加鎖。
3.加鎖和解鎖必須是同一個(gè)線(xiàn)程。
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://m.specialneedsforspecialkids.com/yun/125953.html
摘要:作為面試官,我是如何甄別應(yīng)聘者的包裝程度語(yǔ)言和等其他語(yǔ)言的對(duì)比分析和主從復(fù)制的原理詳解和持久化的原理是什么面試中經(jīng)常被問(wèn)到的持久化與恢復(fù)實(shí)現(xiàn)故障恢復(fù)自動(dòng)化詳解哨兵技術(shù)查漏補(bǔ)缺最易錯(cuò)過(guò)的技術(shù)要點(diǎn)大掃盲意外宕機(jī)不難解決,但你真的懂?dāng)?shù)據(jù)恢復(fù)嗎每秒 作為面試官,我是如何甄別應(yīng)聘者的包裝程度Go語(yǔ)言和Java、python等其他語(yǔ)言的對(duì)比分析 Redis和MySQL Redis:主從復(fù)制的原理詳...
摘要:作為面試官,我是如何甄別應(yīng)聘者的包裝程度語(yǔ)言和等其他語(yǔ)言的對(duì)比分析和主從復(fù)制的原理詳解和持久化的原理是什么面試中經(jīng)常被問(wèn)到的持久化與恢復(fù)實(shí)現(xiàn)故障恢復(fù)自動(dòng)化詳解哨兵技術(shù)查漏補(bǔ)缺最易錯(cuò)過(guò)的技術(shù)要點(diǎn)大掃盲意外宕機(jī)不難解決,但你真的懂?dāng)?shù)據(jù)恢復(fù)嗎每秒 作為面試官,我是如何甄別應(yīng)聘者的包裝程度Go語(yǔ)言和Java、python等其他語(yǔ)言的對(duì)比分析 Redis和MySQL Redis:主從復(fù)制的原理詳...
閱讀 3540·2023-04-25 20:09
閱讀 3743·2022-06-28 19:00
閱讀 3064·2022-06-28 19:00
閱讀 3087·2022-06-28 19:00
閱讀 3178·2022-06-28 19:00
閱讀 2883·2022-06-28 19:00
閱讀 3051·2022-06-28 19:00
閱讀 2641·2022-06-28 19:00