目錄
1. 如何實現(xiàn)分布式鎖
2. Redis 分布式鎖存在什么問題
2.1 解決死鎖問題
2.2 解決鎖誤刪問題
1. 如何實現(xiàn)分布式鎖
Redis 天生就可以作為一個分布式系統(tǒng)來使用,所以它實現(xiàn)的鎖都是分布式鎖。
Redis 可以通過 setnx(set if not exists)命令實現(xiàn)分布式鎖~
- setnx mylock true? -? 加鎖
- del mylock? -? 釋放鎖
通過執(zhí)行結(jié)果是否為 1 可以判斷是否成功獲取到鎖~
2. Redis 分布式鎖存在什么問題
Redis 分布式鎖存在兩個問題:
1.死鎖問題:未設(shè)置過期時間,鎖忘記釋放,加鎖后還沒來的及釋放鎖就宕機(jī)了都會導(dǎo)致死鎖問題.
2. 鎖誤刪問題:設(shè)置了超時時間,但是線程執(zhí)行超過超時時間后鎖誤刪問題.
2.1 解決死鎖問題
????????MySQL 中解決死鎖問題是通過設(shè)置超時時間,Redis 也是如此,但是問題來了,第一步先加鎖,然后再設(shè)置超時時間,那么就不滿足原子性了,那么怎么辦 ?
????????官方在 Redis 2.6.12 版本之后,新增了一個功能,我們可以使用一條命令既執(zhí)行加鎖操作,又設(shè)置超時時間:setnx 和 expire
- 第一條命令成功加鎖,并設(shè)置 30 s 過期時間
- 第二條命令跟在第一條命令后,還沒有超過 30s,所以獲取失敗
2.2 解決鎖誤刪問題
鎖誤刪問題是解決死鎖問題帶來的問題,如何理解 ?
既然知道了什么是鎖誤刪問題,那么如何解決 ?
答:可以通過添加鎖標(biāo)識來解決.
????????前面我們使用 set 命令的時候,只使用到了 key,那么可以給?value 設(shè)置一個標(biāo)識,表示當(dāng)前鎖歸屬于那個線程,例如 value=thread1,value=thread2.....
但是這樣解決依然存在問題,因為新增鎖標(biāo)識之后,線程在釋放鎖的時候,需要執(zhí)行兩步操作了:
- 判斷鎖是否屬于自己
- 如果是,就刪除鎖
這樣就不能保證原子性了,那該怎么辦?
【解決方案】
- 使用 lua 腳本來解決 (Redis 本身就能保證 lua 腳本里面所有命令都是原子性操作)
- 使用 Redisson 框架來解決(主流)
那么 Redisson 如何實現(xiàn)分布式鎖呢 ?
【代碼示例】
1.引入 Redisson?依賴
<dependency>
<groupId>org.redisson</groupId>
<artifactId>redisson-spring-boot-starter</artifactId>
<version>3.23.2</version>
</dependency>
2.創(chuàng)建 RedissonClient 對象
@Configuration
public class RedissonConfig {
@Bean
public RedissonClient redissonClient() {
Config config = new Config();
config.useSingleServer().setAddress("redis://127.0.0.1:6379");
// 如果有密碼需要設(shè)置密碼
return Redisson.create(config);
}
}
3.調(diào)用分布式鎖
@RestController
public class LockController {
@Resource
private RedissonClient redissonClient;
@RequestMapping("/lock")
public String lockResource() throws InterruptedException {
String lockKey = "myLock";
// 獲取鎖
RLock lock = redissonClient.getLock(lockKey);
try {
// 超時時間 10s, [tryLock 獲取成功才需要釋放鎖,獲取失敗不需要釋放鎖]
boolean isLocked = lock.tryLock(20, TimeUnit.SECONDS);
if(isLocked) {
// 成功獲取到鎖
try {
TimeUnit.SECONDS.sleep(5);
return "成功獲取到鎖,并執(zhí)行業(yè)務(wù)代碼";
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
// 釋放鎖
lock.unlock();
}
} else {
// 獲取鎖失敗
return "獲取鎖失敗";
}
} catch (InterruptedException e) {
e.printStackTrace();
}
return "獲取鎖成功";
}
}
啟動項目,使用 8080 端口訪問接口:文章來源:http://www.zghlxwxcb.cn/news/detail-665503.html
文章來源地址http://www.zghlxwxcb.cn/news/detail-665503.html
到了這里,關(guān)于Redis 分布式鎖存在什么問題 ?如何解決 ?的文章就介紹完了。如果您還想了解更多內(nèi)容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!