只是做個簡單的demo測試使用(核心代碼)
/**
* 單體架構(gòu),沒有添加鎖(可以使用Synchronization實現(xiàn)單體架構(gòu)同步代碼塊)
* */
@RequestMapping("/getVlaue")
public String getVlaue(){
// redisTemplate.opsForValue().set("num","100");
int num = Integer.parseInt(redisTemplate.opsForValue().get("num"));
if(num>0){
num = num -1;
redisTemplate.opsForValue().set("num",zs+"");
}else{
System.out.println("庫存不足");
}
System.out.println(redisTemplate.opsForValue().get("num"));
return redisTemplate.opsForValue().get("num");
}
使用redis
//redis實現(xiàn)(存在兩個問題
// 1.高并發(fā)的情況下底燎,如果兩個線程同時進入循環(huán)佛纫,可能導致加鎖失敗。
// 2.SETNX 是一個耗時操作售葡,因為它需要判斷 Key 是否存在,因為會存在性能問題。)
@RequestMapping("/getRedis")
public String getRedis(){
String lock ="lock";
//為了避免本線程刪除其他線程的鎖饶唤,為每個線程的鎖設(shè)置唯一的指
String clientId = UUID.randomUUID().toString();
try {
// //1.獲取鎖
// redisTemplate.opsForValue().set(lock,clientId);
// //2.設(shè)置過期時間
// redisTemplate.expire(lock,10,TimeUnit.SECONDS);
//為保證程序的原子性蓝翰,把1 2兩步合并
Boolean result = redisTemplate.opsForValue().setIfAbsent(lock,clientId,10,TimeUnit.SECONDS);
if(!result){
System.out.println("error");
return "error";
}
int num = Integer.parseInt(redisTemplate.opsForValue().get("num"));
if(num > 0){
num = num -1;//
redisTemplate.opsForValue().set("num",num+"");
System.out.println("剩余"+num);
}else{
System.out.println("庫存不足");
}
}finally {
//只有值為本線程的值時才釋放鎖
if(clientId.equals(redisTemplate.opsForValue().get("lock"))){
redisTemplate.delete(lock);
}
}
return redisTemplate.opsForValue().get("num");
}
使用redisson光绕,簡單實用
//合適解決方案
@RequestMapping("/getRedisson")
public String getRedisson(){
String lockKey = "lock";
String clientId = UUID.randomUUID().toString();
//獲取鎖
RLock lock =redisson.getLock(lockKey);
try {
//加鎖
lock.lock(30,TimeUnit.SECONDS);
int num = Integer.parseInt(redisTemplate.opsForValue().get("num"));
if(num>0){
num = num -1;
redisTemplate.opsForValue().set("num",num+"");
System.out.println("剩余"+num);
}else{
System.out.println("庫存不足");
}
}finally {
//釋放鎖
lock.unlock();
}
return redisTemplate.opsForValue().get("num");
}
使用jMeter測試
image.png
image.png