最简单的分布式锁
例如在更改商品库存时,我们可以对每个商品加锁
通过setnx实现,只有key不存在时,才可以执行成功
@GetMapping("/test4")
public String test4(){
String lock="lock:product_id";
String uuid = UUID.randomUUID().toString();
//设置超时时间为了防止宕机时,来不及释放锁,别的线程抢不到锁,造成死锁
boolean result=template.opsForValue().setIfAbsent(lock,uuid,10, TimeUnit.SECONDS);
if(!result){
return "error_code";
}
//防止出现异常是,来不及释放锁
try {
int id_stock=Integer.parseInt(template.opsForValue().get("id_stock"));
if(id_stock>0){
template.opsForValue().set("id_stock",""+(id_stock-1));
}else{
return "库存不足";
}
}finally {
//加锁和释放锁是同一个
if (uuid.equals(template.opsForValue().get(lock))) {
template.delete(lock);
}
}
return ""+result;
}
但是仍然存在问题:当在释放锁之前程序已经执行的时间超过了锁寿命,锁已经被释放,此时别的线程就可以抢锁,就会出现问题。
Redisson 分布式锁
需要引入如下依赖
<dependency>
<groupId>org.redisson</groupId>
<artifactId>redisson</artifactId>
<version>3.6.5</version>
</dependency>
自定义Redisson
@Bean
public Redisson getRedisson(){
Config config=new Config();
config.useSingleServer().setAddress("192.168.93.101:6379").setDatabase(0);
return (Redisson) Redisson.create(config);
}
@GetMapping("/test5")
public String test5() {
String lock = "lock:product_id";
RLock redissonLock=redisson.getLock(lock);
redissonLock.lock();
try {
int id_stock = Integer.parseInt(template.opsForValue().get("id_stock"));
if (id_stock > 0) {
template.opsForValue().set("id_stock", "" + (id_stock - 1));
} else {
return "库存不足";
}
} finally {
redissonLock.unlock();
}
return "success";
}
分布式锁性能优化
粒度
对于不存在并发安全问题的代码,不要给它加锁,不要放在加锁代码块里。尽量降低锁粒度
后续还有