文章引用:https://mp.weixin.qq.com/s/XgdKE2rBKL0-nFk2NJPuyg
一、单个服务
1.代码
该接口的作用是累加一个值,访问一次该值加1
java
@RestController
public class LockController {
@Autowired
private StringRedisTemplate stringRedisTemplate;
@GetMapping("/increment")
public String increment() {
int counter = Integer.parseInt(stringRedisTemplate.opsForValue().get("count"));
counter++;
System.out.println("当前结果:" + counter);
stringRedisTemplate.opsForValue().set("count", String.valueOf(counter));
return "结果:" + counter;
}
}
2.jmeter工具压测
用100个线程,每个线程访问100次去压测,理论上该值最后应该返回10000
3.结果
发生了线程安全问题,部分请求返回结果相同
4.解决办法:加锁
java
@RestController
public class LockController {
@Autowired
private StringRedisTemplate stringRedisTemplate;
@GetMapping("/increment")
public synchronized String increment() {
int counter = Integer.parseInt(stringRedisTemplate.opsForValue().get("count"));
counter++;
System.out.println("当前结果:" + counter);
stringRedisTemplate.opsForValue().set("count", String.valueOf(counter));
return "结果:" + counter;
}
}

在非集群模式下,简单上锁能解决线程安全问题。
二、集群模式
代码相同,idea启动两个相同的服务
1.启动两个服务

2.nginx配置负载均衡
xml
upstream backend {
# 定义后端服务器列表
server localhost:8081;
server localhost:8082;
}
server {
listen 8080;
location / {
# 将请求代理到后端服务器
proxy_pass http://backend;
}
}
3.jmeter工具压测
用100个线程,每个线程访问100次去压测,理论上该值最后应该返回10000
还是出了线程安全问题,synchronized只能锁住单个服务
三、SpringBoot整合Redisson(注解方式)
1.依赖和配置文件
xml
<dependencies>
<!-- Spring Boot Starter for Web -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- Redisson Dependency-->
<dependency>
<groupId>org.redisson</groupId>
<artifactId>redisson-spring-boot-starter</artifactId>
<version>3.17.6</version><!-- 请根据需要调整版本 -->
</dependency>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.8.10</version>
</dependency>
</dependencies>
yaml
spring:
redis:
host:localhost
port:6379
# Redisson configuration
redisson:
single-server-address:redis://@localhost:6379
2.代码
注解
java
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface DistributedLock {
String lockName();
}
切面
java
@Aspect
@Component
public class DistributedLockAspect {
@Autowired
private RedissonClient redissonClient;
@Around("@annotation(DistributedLock)")
public Object around(ProceedingJoinPoint joinPoint) throws Throwable {
MethodSignature signature = (MethodSignature) joinPoint.getSignature();
DistributedLock annotation = signature.getMethod().getAnnotation(DistributedLock.class);
String lockName = annotation.lockName();
RLock lock = redissonClient.getLock(lockName);
try {
// 尝试获取锁,最多等待10秒,持有锁的时间为30秒
if (!lock.tryLock(10, 30, TimeUnit.SECONDS)) {
throw new RuntimeException("Failed to acquire lock.");
}
return joinPoint.proceed();
} finally {
// 确保在任何情况下都能释放锁
if (lock.isHeldByCurrentThread()) {
lock.unlock();
}
}
}
}
接口
java
@RestController
public class LockController {
@Autowired
private StringRedisTemplate stringRedisTemplate;
@GetMapping("/increment")
@DistributedLock(lockName = "counterLock")
public String increment() {
int counter = Integer.parseInt(stringRedisTemplate.opsForValue().get("count"));
counter++;
System.out.println("当前结果:" + counter);
stringRedisTemplate.opsForValue().set("count", String.valueOf(counter));
return "结果:" + counter;
}
}
3.结果
实现了分布式锁,俩个服务依次接受了所有请求,并无重复值