这篇文章主要介绍了Spring Boot 集成Redisson实现分布式锁详细案例,文章围绕主题展开详细的内容介绍,具有一定的参考价值,需要的朋友可以参考一下
前言
Spring Boot集成Redis实现单机分布式锁针对单机分布式锁还是存在锁定续期、可重入的问题,本文将采用Spring Boot 集成Ression实现分布式锁进行详细讲解。
分布式锁实现
引入jar包
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
<exclusions>
<exclusion>
<groupId>io.lettuce</groupId>
<artifactId>lettuce-core</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.redisson</groupId>
<artifactId>redisson-spring-boot-starter</artifactId>
<version>3.13.6</version>
</dependency>
说明:关于集成Redisson,我们需要注意与Spring Boot的版本对应。
具体对应的关系如下:
注意:3.13.6对应的Spring Boot的版本为2.3.0,而redis-spring-data为redis-spring-data-23。我们可以通过查看pom文件的引用从而得到依赖关系。
Redisson的配置
application.yml中引入redisson.yml配置
redis:
redisson:
file: classpath:redisson.yml
redisson.yml配置
singleServerConfig:
password: xxxx
address: "redis://127.0.0.1:6379"
database: 1
threads: 0
nettyThreads: 0
codec: !<org.redisson.codec.FstCodec> {}
transportMode: "NIO"
说明:本文配置的是单机环境,如果需要配置集群环境,可以采用如下配置:
clusterServersConfig:
idleConnectionTimeout: 10000
connectTimeout: 10000
timeout: 3000
retryAttempts: 3
retryInterval: 1500
failedSlaveReconnectionInterval: 3000
failedSlaveCheckInterval: 60000
password: null
subscriptionsPerConnection: 5
clientName: null
loadBalancer: !<org.redisson.connection.balancer.RoundRobinLoadBalancer> {}
subscriptionConnectionMinimumIdleSize: 1
subscriptionConnectionPoolSize: 50
slaveConnectionMinimumIdleSize: 24
slaveConnectionPoolSize: 64
masterConnectionMinimumIdleSize: 24
masterConnectionPoolSize: 64
readMode: "SLAVE"
subscriptionMode: "SLAVE"
nodeAddresses:
- "redis://127.0.0.1:7004"
- "redis://127.0.0.1:7001"
- "redis://127.0.0.1:7000"
scanInterval: 1000
pingConnectionInterval: 0
keepAlive: false
tcpNoDelay: false
threads: 16
nettyThreads: 32
codec: !<org.redisson.codec.MarshallingCodec> {}
transportMode: "NIO"
封装Redisson工具类
@Component
public class RedissonLockUtil
{
private static final Logger logger = LoggerFactory.getLogger(RedissonLockUtil.class);
@Autowired
private RedissonClient redissonClient;
/**
* 加锁
* @param lockKey
* @return
*/
public RLock lock(String lockKey)
{
RLock lock = redissonClient.getLock(lockKey);
return lock;
}
/**
* 公平锁
* @param key
* @return
*/
public RLock fairLock(String key)
{
return redissonClient.getFairLock(key);
}
/**
* 带超时的锁
* @param lockKey
* @param timeout 超时时间 单位:秒
*/
public RLock lock(String lockKey, int timeout)
{
RLock lock = redissonClient.getLock(lockKey);
lock.lock(timeout, TimeUnit.SECONDS);
return lock;
}
/**
* 读写锁
* @param key
* @return
*/
public RReadWriteLock readWriteLock(String key) {
return redissonClient.getReadWriteLock(key);
}
/**
* 带超时的锁
* @param lockKey
* @param unit 时间单位
* @param timeout 超时时间
*/
public RLock lock(String lockKey, TimeUnit unit ,int timeout) {
RLock lock = redissonClient.getLock(lockKey);
lock.lock(timeout, unit);
return lock;
}
/**
* 加锁
* @param key
* @param supplier
* @return
*/
public <T> T lock(String key, Supplier<T> supplier) {
RLock lock = lock(key);
try {
lock.lock();
return supplier.get();
} finally {
if (lock != null && lock.isLocked()) {
lock.unlock();
}
}
}
/**
* 尝试获取锁
* @param lockKey
* @param waitTime 等待时间
* @param leaseTime 自动释放锁时间
* @return
*/
public boolean tryLock(String lockKey, int waitTime, int leaseTime) {
RLock lock = redissonClient.getLock(lockKey);
try {
return lock.tryLock(waitTime, leaseTime, TimeUnit.SECONDS);
} catch (InterruptedException e) {
return false;
}
}
/**
* 尝试获取锁
* @param lockKey
* @param unit 时间单位
* @param waitTime 等待时间
* @param leaseTime 自动释放锁时间
* @return
*/
public boolean tryLock(String lockKey, TimeUnit unit, int waitTime, int leaseTime) {
RLock lock = redissonClient.getLock(lockKey);
try {
return lock.tryLock(waitTime, leaseTime, unit);
} catch (InterruptedException e) {
return false;
}
}
/**
* 释放锁
* @param lockKey
*/
public void unlock(String lockKey) {
RLock lock = redissonClient.getLock(lockKey);
lock.unlock();
}
/**
* 释放锁
* @param lock
*/
public void unlock(RLock lock)
{
lock.unlock();
}
}
模拟秒杀扣减库存
public int lockStock()
{
String lockKey="lock:stock";
String clientId = UUID.randomUUID().toString();
//加锁
RLock lock=redissonLockUtil.lock(lockKey);
lock.lock();
try
{
logger.info("加锁成功 clientId:{}",clientId);
int stockNum= Integer.valueOf((String)redisUtil.get("seckill:goods:stock"));
if(stockNum>0)
{
stockNum--;
redisUtil.set("seckill:goods:stock",String.valueOf(stockNum));
logger.info("秒杀成功,剩余库存:{}",stockNum);
}
else
{
logger.error("秒杀失败,剩余库存:{}", stockNum);
}
//获取库存数量
return stockNum;
}
catch (Exception e)
{
logger.error("decry stock eror",e);
}
finally
{
if(lock!=null)
{
lock.unlock();
}
}
return 0;
}
测试代码
@RequestMapping("/redisLockTest")
public void redisLockTest()
{
// 初始化秒杀库存数量
redisUtil.set("seckill:goods:stock", "10");
List<Future> futureList = new ArrayList<>();
//多线程异步执行
ExecutorService executors = Executors.newScheduledThreadPool(10);
//
for (int i = 0; i < 30; i++)
{
futureList.add(executors.submit(this::lockStock));
try
{
Thread.sleep(100);
}
catch (InterruptedException e)
{
logger.error("redisLockTest error",e);
}
}
// 等待结果,防止主线程退出
futureList.forEach(t -> {
try
{
int stockNum =(int) t.get();
logger.info("库存剩余数量:{}",stockNum);
}
catch (Exception e)
{
logger.error("get stock num error",e);
}
});
}
执行结果如下:
总结
本文针对Spring Boot集成Redisson的基本使用,关于Redisson源码的分析将在后续的文章中进行讲解,如有疑问,请随时反馈,
沃梦达教程
本文标题为:Spring Boot 集成Redisson实现分布式锁详细案例
基础教程推荐
猜你喜欢
- JDK数组阻塞队列源码深入分析总结 2023-04-18
- ConditionalOnProperty配置swagger不生效问题及解决 2023-01-02
- java实现多人聊天系统 2023-05-19
- springboot自定义starter方法及注解实例 2023-03-31
- java基础知识之FileInputStream流的使用 2023-08-11
- Java实现查找文件和替换文件内容 2023-04-06
- Java实现线程插队的示例代码 2022-09-03
- Java数据结构之对象比较详解 2023-03-07
- Java文件管理操作的知识点整理 2023-05-19
- Java并发编程进阶之线程控制篇 2023-03-07