如何利用Redis分布式锁处理高并发?
一、添加项目依赖
<!-- redis依赖 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
二、配置文件
spring:
redis:
host: localhost
password: 123456
三、模拟 抢购商品 的 Service 层
public interface SellService {
String orderGoods(String productId);
String queryGoods(String productId);
}
@Service
@Slf4j
public class SellServiceImpl implements SellService {
@Autowired
private RedisLock redisLock;
private static final int TIMEOUT = 10*1000;
static Map<String, Integer> products;
static Map<String, Integer> stock;
static Map<String, String> orders;
static {
products = new HashMap<>();
stock = new HashMap<>();
orders = new HashMap<>();
products.put("book", 1000);
stock.put("book", 1000);
}
public String queryMap(String productId){
return "国庆图书大甩卖,库存 " + products.get(productId) + " 件,现余 " + stock.get(productId) + " 件,已被抢购 " + orders.size() + " 件";
}
@Override
public String orderGoods(String productId) {
int number = stock.get(productId);
if(number == 0){
throw new RuntimeException("商品已抢购完,请您下次再来,谢谢您的理解...");
}else {
orders.put(String.valueOf(UUID.randomUUID()), productId);
number = number - 1;
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
stock.put(productId, number);
}
log.info("共抢购 {} 件,抢购详情:{}", orders.size(), orders);
return this.queryMap(productId);
}
@Override
public String queryGoods(String productId) {
return this.queryMap(productId);
}
}
四、Controller 层
@RestController
public class SellController {
@Autowired
private SellService sellService;
@GetMapping("/order/{productId}")
public String sellGoods(@PathVariable String productId){
return sellService.orderGoods(productId);
}
@GetMapping("/query/{productId}")
public String queryGoods(@PathVariable String productId){
return sellService.queryGoods(productId);
}
}
五、模拟高并发
ab -n 500 -c 80 http://localhost:8080/order/book

六、结果

七、利用Redis分布式锁 解决高并发问题
1、实现Redis分布式锁
@Component
@Slf4j
public class RedisLock {
@Autowired
private StringRedisTemplate redisTemplate;
public boolean lock(String key, String value){
if(redisTemplate.opsForValue().setIfAbsent(key, value)){
return true;
}
String currentValue = redisTemplate.opsForValue().get(key);
if(!StringUtils.isEmpty(currentValue) && Long.parseLong(currentValue) < System.currentTimeMillis()){
String oldValue = redisTemplate.opsForValue().getAndSet(key, value);
if(!StringUtils.isEmpty(oldValue) && currentValue.equals(oldValue)){
return true;
}
}
return false;
}
public void unlock(String key, String value){
try{
String currentValue = redisTemplate.opsForValue().get(key);
if(!StringUtils.isEmpty(currentValue) && currentValue.equals(value)){
redisTemplate.opsForValue().getOperations().delete(key);
}
}catch (Exception e){
log.error("【Redis分布式锁】 解锁异常 {}", e.getMessage());
}
}
}
2、利用分布式锁处理Service层方法
@Override
public String orderGoods(String productId) {
Long time = System.currentTimeMillis() + TIMEOUT;
if(!redisLock.lock(productId, String.valueOf(time))){
log.info("抢购失败,请再试试吧...");
throw new RuntimeException("服务器刚才好像睡着了,请再试试吧...");
}
int number = stock.get(productId);
if(number == 0){
throw new RuntimeException("商品已抢购完,请您下次再来,谢谢您的理解...");
}else {
orders.put(String.valueOf(UUID.randomUUID()), productId);
number = number - 1;
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
stock.put(productId, number);
}
log.info("共抢购 {} 件,抢购详情:{}", orders.size(), orders);
redisLock.unlock(productId, String.valueOf(time));
return this.queryMap(productId);
}
八、模拟高并发
ab -n 500 -c 80 http://localhost:8080/order/book

九、结果

