1、先说一下synchronized(集群下锁失效)
@RestController
public class IndexController {
@Autowired
private RedisTemplate<String, String> redisTemple;
@RequestMapping("/deductStock")
public String deductStock() {
synchronized (this) {
/*synchronized对单体项目还可以,对分布式集群部署项目不起作用。举例说明:我有2台服务器,通过nginx代理了,分别为tomcat1和tomcat2,设置redis库存为100,高并发场景
当第一次分发到tomcat1中,第二次请求分发到tomcat中,如果tomcat1中程序还没执行完,还没减库存,tomcat2中已经获取了redis中的库存,值还是100,这样
synchronized在集群中就无法起到锁的作用。如下图所示*/
int stock = Integer.parseInt(redisTemple.opsForValue().get("stock"));
if(stock > 0) {
int realStock = stock - 1;
redisTemple.opsForValue().set("stock",realStock+"");
System.err.println("扣减成功,当前库存为"+realStock);
}else {
System.err.println("扣减失败,库存不足!");
}
}
return "";
}
}
2、Redis的SETNX实现锁机制(基本解决分布式锁,性能上还存在问题)
@RestController
public class IndexController {
@Autowired
private RedisTemplate<String, String> redisTemple;
@RequestMapping("/deductStock")
public String deductStock() {
String lockKey="product_001";
String clientId=UUID.randomUUID().toString();
//Redis的SETNX实现锁机制(也就是只有不存在的时候才设置,可以利用它来实现锁的效果)
try {
// Boolean result = redisTemple.opsForValue().setIfAbsent(lockKey, "lzp");//就相当于jedis.setnx(k,v)
// redisTemple.expire(lockKey, 10, TimeUnit.SECONDS);
//以上2行也会存在问题,例如执行完第一行服务就挂了,锁就没有过期时间,一直不被释放;所以用下边的重载方法,具有原子性
Boolean result = redisTemple.opsForValue().setIfAbsent(lockKey, clientId, 10, TimeUnit.SECONDS);
if (!result) {
return "很抱歉未抢到!";
}
//具体业务逻辑
int stock = Integer.parseInt(redisTemple.opsForValue().get("stock"));
if (stock > 0) {
int realStock = stock - 1;
redisTemple.opsForValue().set("stock", realStock + "");
System.err.println("扣减成功,当前库存为" + realStock);
} else {
System.err.println("扣减失败,库存不足!");
}
} finally {
if(clientId.equals(redisTemple.opsForValue().get(lockKey))) {//确认是关闭的自己锁
//释放锁
redisTemple.delete(lockKey);
}
}
return "";
}
}
3、基于redission的分布式锁
引入pom.xml依赖
<dependency>
<groupId>org.redisson</groupId>
<artifactId>redisson</artifactId>
<version>3.2.3</version>
</dependency>