在分布式系统架构下,由于并发可能带来的线程操作安全问题。
例如线程1在对某个对象执行业务时,线程2也同时对这个对象进行同样操作,两个线程的同时操做可能会导致业务的重复办理,导致异常。针对与这种问题,可以引入Redisson用来解决这个问题。Redisson 是基于Netty框架,兼容Redis 3.0+ 和 JDK 1.8+,可以简单轻松的整合到SpringBoot项目中。
此次演示的案例是基于 JDK1.8 + SpringBoot 2.6.13 + maven 3.8.2 + redis 5.0.14 + redisson 3.16.0。配置的redis为单机模式,更多配置详细信息,可以点击连接进行查阅 redisson官方文档
1、引入 Redisson 依赖
将以下配置添加到pom文件中,导入redisson依赖包
<dependency>
<groupId>org.redisson</groupId>
<artifactId>redisson</artifactId>
<version>3.16.0</version>
</dependency>
2、创建 Redisson 配置类
演示案例连接的redis是本机启动的服务,所以直接将连接地址写在了创建的过程中。如果启用的是集群模式,可以将具体的配置写在yaml配置文件中。具体的配置方式可以查看官网的配置文档
@Configuration
public class RedissonConfig {
@Bean
public RedissonClient redissonClient() {
Config config = new Config();
config.useSingleServer()
.setAddress("redis://127.0.0.1:6379");
return Redisson.create(config);
}
}
3、创建 Redisson 使用案例
注意: 解锁方法一定要放在
finally里面执行,避免因异常出现导致锁无法解除
创建RedissonTestService类,其中有两个方法,分别为concurrentTest和redissonLock
- concurrentTest,用模拟并发操作,创建创建多个线程执行业务方法
- redissonLock,用于模拟业务操作,在业务操作之前进行加锁,通过睡眠模拟业务执行时间
- tryLock(),redisson上锁的方法,如果其他线程已经上锁,那么当前线程就无法获取到锁,方法返回结果就为false
- isHeldByCurrentThread(),用来判断锁是否为当前线程添加,返回boolean类型
- unlock(),解除锁的方法
@Service
public class RedissonTestService {
@Resource
private RedissonClient redissonClient;
public void concurrentTest() {
// 创建两个线程模拟并发操作
Thread thread1 = new Thread(this::redissonLock, "t1");
Thread thread2 = new Thread(this::redissonLock, "t2");
thread1.start();
thread2.start();
}
public void redissonLock() {
RLock lock = redissonClient.getLock("myLock");
try {
if (lock.tryLock()) {
System.out.println(Thread.currentThread().getName() + " - 获取到锁");
// 睡眠模拟业务操作
Thread.sleep(5000);
} else {
System.out.println(Thread.currentThread().getName() + " - 获取锁失败!");
}
} catch (InterruptedException e) {
throw new RuntimeException(e.getMessage());
} finally {
if (lock.isHeldByCurrentThread()) {
lock.unlock(); // 解锁
System.out.println(Thread.currentThread().getName() + " - 解除锁");
}
}
}
}
4、创建 Controller 进行测试
创建controller,用于前台访问进行测试的入口,调用service的测试案例
@RestController
public class RedissonTestController {
@Resource
private RedissonTestService lockService;
// 浏览器调用模拟操作业务
@GetMapping("/test-redisson-lock")
public String testRedissonLock() {
lockService.concurrentTest();
return "进行redisson分布式锁测试!";
}
}
5、测试
测试结果
t1 - 获取锁失败!
t2 - 获取到锁
t2 - 解除锁
t1 - 获取到锁
t2 - 获取锁失败!
t1 - 解除锁
通过观察以上测试输出结果可以方法,当其中一个线程获取到锁之后,另外一个线程无法直接获取到锁。直到锁解除之后,再次调用两个线程再竞争获取锁
总结
在分布式结构的系统下,对业务进行配置锁是十分有必要的,可以有效的保证业务的执行安全,Redisson可以通过简单的配置整合到SpringBoot项目之中,可以轻松实现Redis 的分布式锁机制,确保不会被重复执行或执行出错
以上就是基于Redisson实现的分布式锁的简单演示案例