减少库存
编写最普通的程序,不考虑任何并发的代码
10000
库存,访问一次接口库存减1
0
,返回库存不足springboot
项目快速创建springboot
项目,这里不重复赘述了。快速通道10000
次或者更多,才能获得较准确的结果ok
,多余的没什么了,先编写代码试试新建controller
->StringRedisTestController
static
变量->nowCount
,用来做全局值统一nowCount
减一,直到小于等于0
为止编写完成的代码如下:
package com.yxj.spring.controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
/**
* @version v1.0
* @Copyright(c): 2020-2020
* @FileName: RedisTestController.java
* @Description:
* @autho Admin
* @date 2020/1/17 13:55
*/
@RestController
@RequestMapping("/test")
public class StringRedisTestController {
private static Integer nowCount = 10000;
/**
* 减少,库存等等
* @return
*/
@GetMapping("/redis/reduce")
public String lockTest(){
if(nowCount<=0){
System.out.println("------库存不足------");
return "------库存不足------";
}
--nowCount;
System.out.println("----库存剩余----"+nowCount);
return String.valueOf(nowCount);
}
}
jmeter
,我的版本号apache-jmeter-2.12
10000
次http
请求,这里写controller
的请求路径因为代码较多,这里我只贴出最终结果
----库存剩余----4
----库存剩余----3
----库存剩余----2
----库存剩余----1
----库存剩余----0
结果正常
static
变量赋值)----库存剩余----4
----库存剩余----3
----库存剩余----2
----库存剩余----1
----库存剩余----0
结果正常
----库存剩余----4
----库存剩余----3
----库存剩余----2
----库存剩余----1
----库存剩余----0
结果正常
综上所诉,单线程访问代码,是没有什么问题
jemeter
设置的线程组,将线程数更改为两个或者更多10000
2
个线程,循环次数5000
static
的值)----库存剩余----2699
----库存剩余----2698
----库存剩余----2696
----库存剩余----2696
可以看到,数据已经错乱了,还有重复值
使用JAVA原生锁
package com.yxj.spring.controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.util.Date;
/**
* @version v1.0
* @Copyright(c): 2020-2020
* @FileName: RedisTestController.java
* @Description:
* @autho Admin
* @date 2020/1/17 13:55
*/
@RestController
@RequestMapping("/test")
public class StringRedisTestController {
private static Integer nowCount = 10000;
/**
* 减少,库存等等
* @return
*/
@GetMapping("/redis/reduce")
public synchronized String lockTest(){
if(nowCount<=0){
System.out.println("------库存不足------");
return "------库存不足------";
}
--nowCount;
System.out.println("----库存剩余----"+nowCount);
return String.valueOf(nowCount);
}
}
----库存剩余----3
----库存剩余----2
----库存剩余----1
----库存剩余----0
可以看到,结果又正常了
synchronized
确实可以解决库存不一致问题,但是,因为线上服务大部分都是多节点部署,两台或者两天以上的服务器,代码加synchronized
肯定是不好使的
所以这里推荐使用redis
锁
redis
锁基于redis
实现redis
是单线程,安全setIfAbsent
来判断key
是否存在expire
来设置超时时间delete
来删除key
package com.yxj.spring.controller;
import com.yxj.spring.utils.RedisUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.util.Date;
import java.util.concurrent.TimeUnit;
/**
* @version v1.0
* @Copyright(c): 2020-2020
* @FileName: RedisTestController.java
* @Description:
* @autho Admin
* @date 2020/1/17 13:55
*/
@RestController
@RequestMapping("/test")
public class StringRedisTestController {
@Autowired
private RedisUtils redisUtils;
private static Integer nowCount = 10000;
/**
* 减少,库存等等
* @return
*/
@GetMapping("/redis/reduce")
public String lockTest(){
if(nowCount<=0){
System.out.println("------库存不足------");
return "------库存不足------";
}
if(redisUtils.setIfAbsent(String.valueOf(nowCount), "true")){
redisUtils.expire(String.valueOf(nowCount),1,TimeUnit.SECONDS);
Integer count = nowCount;
--nowCount;
redisUtils.delete(String.valueOf(count));
System.out.println("----库存剩余----"+nowCount);
return String.valueOf(nowCount);
}else{
System.out.println("系统繁忙");
return "系统繁忙";
}
}
}
两个线程再跑,第一个线程redis key
还没有删除,第二个线程已经进入方法了,所以被拦截,无法执行
----库存剩余----4525
系统繁忙
----库存剩余----4524
系统繁忙
----库存剩余----4523
系统繁忙
----库存剩余----4522
系统繁忙
----库存剩余----4521
系统繁忙
----库存剩余----4520
系统繁忙
----库存剩余----4519
系统繁忙
----库存剩余----4518
系统繁忙
----库存剩余----4517
系统繁忙
----库存剩余----4516
系统繁忙
----库存剩余----4515
----库存剩余----4514
----库存剩余----4513
系统繁忙
----库存剩余----4512
系统繁忙
----库存剩余----4511
系统繁忙
----库存剩余----4510
----库存剩余----4509
----库存剩余----4508
----库存剩余----4507
----库存剩余----4506
总结
o(╥﹏╥)o
)redis
锁主要用作分布式的安全方面,可以通过最后的redis
锁测试的结果看出,虽然库存没有减到0
,但是安全得到了保障,每个数,只被用了一次StringRedisTemplate
(之前都是使用Jedis
),没有踩过太大的坑,所以不敢保障这个redis
使用一定正确,但是效果达到了redisUtils
,点击下面的阅读原文,即可找着