分布式鎖,就是控制分布式系統(tǒng)中不同進(jìn)程共同訪問同一共享資源的一種鎖的實(shí)現(xiàn)。
1、引入依賴
<dependency>
<groupId>org.redisson</groupId>
<artifactId>redisson-spring-boot-starter</artifactId>
<version>3.15.5</version>
</dependency>
2、配置文件
spring:
data:
redis:
database: 1
host: localhost
port: 6379
password: *********
3、配置類
package com.example.springboot3test.config;
import org.redisson.Redisson;
import org.redisson.api.RedissonClient;
import org.redisson.config.Config;
import org.redisson.config.SingleServerConfig;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
/**
* @author DeyouKong
* @description TODO
* @date 2023/3/23 23:34
*/
@Configuration
public class RedissonConfig {
@Value(value = "${spring.data.redis.host}")
private String host;
@Value(value = "${spring.data.redis.port}")
private int port;
@Value(value = "${spring.data.redis.database}")
private int database;
@Value(value = "${spring.data.redis.password}")
private String password;
/**
* 單Redis節(jié)點(diǎn)模式配置方法
* 其他配置參數(shù),看:
* <a >
* 單Redis節(jié)點(diǎn)模式配置方法
* </a>
*
* @return {@link RedissonClient}
*/
@Bean(destroyMethod = "shutdown")
RedissonClient redisson() {
Config config = new Config();
//Redis多節(jié)點(diǎn)
// config.useClusterServers()
// .addNodeAddress("redis://127.0.0.1:6379", "redis://127.0.0.1:7001");
//Redis單節(jié)點(diǎn)
SingleServerConfig singleServerConfig = config.useSingleServer();
//可以用"rediss://"來啟用SSL連接
String address = "redis://" + host + ":" + port;
singleServerConfig.setAddress(address);
//設(shè)置 數(shù)據(jù)庫(kù)編號(hào)
singleServerConfig.setDatabase(database);
singleServerConfig.setPassword(password);
//連接池大小:默認(rèn)值:64
// singleServerConfig.setConnectionPoolSize()
return Redisson.create(config);
}
}
4、測(cè)試代碼
package com.example.springboot3test.controller;
import jakarta.annotation.Resource;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.concurrent.TimeUnit;
@RestController
@RequestMapping("/redission")
public class RedissionController {
@Resource
private RedissonClient redissonClient;
private final static String LOCK="I_AM_LOCK";
@GetMapping("/list")
public String getString(){
// 1、獲取一把鎖,只要鎖的名字一樣,既是同一把鎖
RLock lock = redissonClient.getLock(LOCK);
// 2、加鎖
//lock.lock(5, TimeUnit.SECONDS); // 阻塞式等待
if(lock.isLocked()){
//如果存在鎖,則返回失敗
return "fail";
}
lock.lock();
try {
System.out.println(Thread.currentThread().getName()+":\t 獲得鎖");
Thread.sleep(20000);
} catch (Exception e) {
e.printStackTrace();
return "占用所";
}finally {
// 3、解鎖
lock.unlock();
System.out.println(Thread.currentThread().getName()+":\t 釋放鎖鎖");
}
return "OK";
}
}
5、理解
一、時(shí)間設(shè)置
默認(rèn) lock() 小結(jié)
lock.lock ();
(1)默認(rèn)指定鎖時(shí)間為30s(看門狗時(shí)間)
(2)鎖的自動(dòng)續(xù)期:若是業(yè)務(wù)超長(zhǎng),運(yùn)行期間自動(dòng)給鎖上新的 30s,不用擔(dān)心業(yè)務(wù)時(shí)間過長(zhǎng),鎖就自動(dòng)過期
(3)加鎖的業(yè)務(wù)只要運(yùn)行完成,就不會(huì)給當(dāng)前鎖續(xù)期,及時(shí)不手動(dòng)解鎖,鎖默認(rèn)在30s 后自動(dòng)刪除。
指定時(shí)間 lock() 小結(jié)
問題:在鎖到期的時(shí)候,不會(huì)自動(dòng)續(xù)期。
(1)如果我們傳遞了鎖的超時(shí)時(shí)間,就發(fā)送給 redis執(zhí)行腳本,進(jìn)行占鎖,默認(rèn)的超時(shí)時(shí)間既我們指的時(shí)間
(2)若是未指定鎖的超時(shí)時(shí)間,就使用 30*1000【LockWatchdogTimeout看門狗的默認(rèn)時(shí)間】
(3)只要占鎖成功,就會(huì)啟動(dòng)一個(gè)定時(shí)任務(wù)【重新給鎖設(shè)置過期時(shí)間,新的過期時(shí)間就是看門狗的默認(rèn)時(shí)間】,每隔 10 s都會(huì)自動(dòng)再次續(xù)到30s, internallockLeaseTime【看門狗時(shí)間/3s】
二、其他
1、互斥
在分布式高并發(fā)的條件下,我們最需要保證,同一時(shí)刻只能有一個(gè)線程獲得鎖,這是最基本的一點(diǎn)。
2、防止死鎖
在分布式高并發(fā)的條件下,比如有個(gè)線程獲得鎖的同時(shí),還沒有來得及去釋放鎖,就因?yàn)橄到y(tǒng)故障或者其它原因使它無法執(zhí)行釋放鎖的命令,導(dǎo)致其它線程都無法獲得鎖,造成死鎖。所以分布式非常有必要設(shè)置鎖的有效時(shí)間,確保系統(tǒng)出現(xiàn)故障后,在一定時(shí)間內(nèi)能夠主動(dòng)去釋放鎖,避免造成死鎖的情況。
6、讀寫鎖
讀寫鎖(Readers-Writer Lock)顧名思義是一把鎖分為兩部分:讀鎖和寫鎖,其中讀鎖允許多個(gè)線程同時(shí)獲得,因?yàn)樽x操作本身是線程安全的,而寫鎖則是互斥鎖,不允許多個(gè)線程同時(shí)獲得寫鎖,并且寫操作和讀操作也是互斥的??偨Y(jié)來說,讀寫鎖的特點(diǎn)是:讀讀不互斥、讀寫互斥、寫寫互斥。
實(shí)現(xiàn):首先要配置redis,見前面的博客文章來源:http://www.zghlxwxcb.cn/news/detail-654978.html
spring boot配置redis
讀寫鎖代碼文章來源地址http://www.zghlxwxcb.cn/news/detail-654978.html
package com.example.springboot3test.controller;
import jakarta.annotation.Resource;
import org.redisson.api.RLock;
import org.redisson.api.RReadWriteLock;
import org.redisson.api.RedissonClient;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.UUID;
import java.util.concurrent.TimeUnit;
@RestController
@RequestMapping("/redission")
public class RedissionController {
@Resource
private RedissonClient redissonClient;
@Resource
private RedisTemplate redisTemplate;
private final static String LOCK="I_AM_LOCK";
// 并發(fā)寫鎖
@GetMapping("/write")
public String writeValue(){
RReadWriteLock myLock = redissonClient.getReadWriteLock ("my_lock");
RLock rLock = myLock.writeLock ( );
rLock.lock ();
String s = "";
try {
System.out.println ("寫鎖加鎖成功..."+Thread.currentThread ().getId () );
s= UUID.randomUUID ().toString ();
Thread.sleep(20000);
redisTemplate.opsForValue ().set ("writeValue",s);
} catch (Exception e) {
e.printStackTrace ();
}
finally {
System.out.println ("寫鎖解鎖成功..."+Thread.currentThread ().getId () );
rLock.unlock ();
}
return s;
}
// 并發(fā)讀鎖
@GetMapping("read")
public String readValue(){
RReadWriteLock myLock = redissonClient.getReadWriteLock ("my_lock");
RLock rLock = myLock.readLock ( );
rLock.lock ();
String s = "";
try {
System.out.println ("讀鎖加鎖成功..."+Thread.currentThread ().getId ());
Thread.sleep(20000);
s = (String) redisTemplate.opsForValue ().get ("writeValue");
} catch (Exception e) {
e.printStackTrace ( );
}finally {
System.out.println ("讀鎖解鎖成功..."+Thread.currentThread ().getId () );
rLock.unlock ();
}
return s;
}
}
到了這里,關(guān)于spring boot 實(shí)現(xiàn)Redisson分布式鎖及其讀寫鎖的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!