更新时间:2021-08-13 10:38:01 来源:极悦 浏览1164次
<!-- redis依赖 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
spring:
#Redis配置
redis:
host: localhost
password: 123456
接口类
/**
* @author 刘路生
*/
public interface SellService {
/**
* 根据商品ID抢购商品并且返回商品的抢购详情
* @param productId
* @return
*/
String orderGoods(String productId);
/**
* 根据商品ID查询商品抢购详情
* @param productId
* @return
*/
String queryGoods(String productId);
}
实现类
@Service
@Slf4j
/**
* @author 刘路生
*/
public class SellServiceImpl implements SellService {
@Autowired
private RedisLock redisLock;
/**
设置超时时间10秒
*/
private static final int TIMEOUT = 10*1000;
/**
* 例如国庆大甩卖 图书大甩卖 库存 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 {
//模拟下单(不同用户拥有不同ID)
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);
}
}
/**
* @author 刘路生
*/
@RestController
public class SellController {
@Autowired
private SellService sellService;
/**
* 根据商品ID进行抢购
* @param productId
* @return 商品抢购详情
*/
@GetMapping("/order/{productId}")
public String sellGoods(@PathVariable String productId){
return sellService.orderGoods(productId);
}
/**
* 根据商品ID进行查询余量
* @param productId
* @return 商品抢购详情
*/
@GetMapping("/query/{productId}")
public String queryGoods(@PathVariable String productId){
return sellService.queryGoods(productId);
}
}
使用 Apache ab 模拟高并发
ab -n 500 -c 80 http://localhost:8080/order/book
(1)实现Redis分布式锁
/**
* @author 刘路生
*/
@Component
@Slf4j
public class RedisLock {
@Autowired
private StringRedisTemplate redisTemplate;
/**
* 加锁
* @param key
* @param value 当前时间+超时时间
* @return
*/
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;
}
/**
* 解锁
* @param key
* @param value 当前时间+超时时间
*/
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层方法
/**
* 第一种方法 synchronized 锁机制,解决高并发产生的超卖问题 但效率大大降低 不推荐使用
* 第二种方法 使用 Redis 分布式锁,解决高并发产生的超卖问题 并且效率相对高很多
*/
@Override
public String orderGoods(String productId) {
//加锁
Long time = System.currentTimeMillis() + TIMEOUT;
//加锁失败 说明有人正在使用
if(!redisLock.lock(productId, String.valueOf(time))){
log.info("抢购失败,请再试试吧...");
//return null;
throw new RuntimeException("服务器刚才好像睡着了,请再试试吧...");
}
//先获取商品余量
int number = stock.get(productId);
if(number == 0){
throw new RuntimeException("商品已抢购完,请您下次再来,谢谢您的理解...");
}else {
//模拟下单(不同用户拥有不同ID)
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);
}
使用 Apache ab 模拟高并发
ab -n 500 -c 80 http://localhost:8080/order/book
浏览器显示
控制台打印
以上就是极悦小编介绍的"利用Redis分布式锁处理高并发",希望对大家有帮助,想了解更多可查看Java极悦在线学习。极悦在线学习教程,针对没有任何Java基础的读者学习,让你从入门到精通,主要介绍了一些Java基础的核心知识,让同学们更好更方便的学习和了解Java编程,感兴趣的同学可以关注一下。
0基础 0学费 15天面授
Java就业班有基础 直达就业
业余时间 高薪转行
Java在职加薪班工作1~3年,加薪神器
工作3~5年,晋升架构
提交申请后,顾问老师会电话与您沟通安排学习