redission实现分布式锁
序言
在使用SETNX实现的分布式锁中,因为存在锁无法续期导致并发冲突的问题,所以在真实的生产环境中用的并不是很多,其实,真正在使用Redis时,用的比较多的是基于Redisson实现分布式锁。
Redisson是一个基于Redis的Java客户端,它提供了丰富的功能,包括分布式锁的支持。 https://redisson.org/关于Redisson实现分布式锁可以查看:https://github.com/redisson/redisson/wiki/8.-Distributed-locks-and-synchronizers
为了避免锁超时,Redisson中引入了看门狗的机制,他可以帮助我们在Redisson实例被关闭前,不断的延长锁的有效期。(默认情况下,看门狗的检查锁的超时时间是30秒钟,也可以通过修改Config.lockWatchdogTimeout来另行指定。)
实现可重入锁
基于Redisson可以非常简单的就获取一个可重入的分布式锁。基本步骤如下:
引入依赖
<dependency>
<groupId>org.redisson</groupId>
<artifactId>redisson</artifactId>
<version>3.0</version>
</dependency>
定义客户端
@Configuration
public class RedissonConfig {
@Bean(destroyMethod="shutdown")
public RedissonClient redisson() throws IOException {
Config config = new Config();
config.useSingleServer().setAddress("redis://127.0.0.1:6379");
RedissonClient redisson = Redisson.create(config);
return redisson;
}
}
在想要使用分布式锁的地方做调用即可
/**
* @Description:
* @author:<a href="2358853434@qq.com"></a> zh
* @Create : 2024/10/4
**/
@Service
@Slf4j
public class OrderServiceimpl implements OrderService {
@Resource
RedisTemplate<String,String> redisTemplate;
@Resource
RedissonClient redisson;
/**
* 更新订单接口
* @param order
* @return
*/
@Log
public Result update(Order order) {
//加锁的代码
RLock lock = redisson.getLock("lock");
try {
lock.lock();
log.info("加锁,当前线程id为:{}", Thread.currentThread().getId());
// 执行需要加锁的代码
redisTemplate.opsForValue().set("order:"+order.getId(), order.toString());
} catch (Exception e){
return Result.error("更新订单失败");
}finally {
lock.unlock();
log.info("解锁,当前线程id为:{}", Thread.currentThread().getId());
}
return Result.success();
}
}
设置超时时间
@Log
public Result update(Order order) {
//加锁的代码
RLock lock = redisson.getLock("order");
try {
lock.lock(30, TimeUnit.SECONDS);
log.info("加锁,当前线程id为:{}", Thread.currentThread().getId());
// 执行需要加锁的代码
redisTemplate.opsForValue().set("order:"+order.getId(), order.toString());
} catch (Exception e){
return Result.error("更新订单失败");
}finally {
lock.unlock();
log.info("解锁,当前线程id为:{}", Thread.currentThread().getId());
}
return Result.success();
}
实现的是一个可重入的分布式锁,也就是说,获取到锁的线程可以再次尝试获取锁,并且这个锁也只能被这个线程解锁。