Redisson实现分布式锁
- Redisson是一个Redis客户端的Java实现,它提供了一系列分布式的工具,包括分布式锁,分布式集合,分布式队列,分布式计数器,分布式阻塞队列等。
- 可以让开发者像使用本地集合一样使用 Redis, 完全感知不到 Redis 的存在.
- Redisson官网
使用Redisson
- 添加Redisson依赖
- spring boot starter 引入(不推荐,版本迭代太快,容易冲突)
- 直接引入redisson依赖(推荐)
<!-- https://mvnrepository.com/artifact/org.redisson/redisson --> <dependency> <groupId>org.redisson</groupId> <artifactId>redisson</artifactId> <version>3.35.0</version> </dependency>
- 配置Redisson
- 新建RedissonConfig类,配置Redis连接信息
@Configuration @ConfigurationProperties(prefix = "spring.data.redis") // 读取配置文件中的redis配置 @Data // lombok注解,自动生成getter、setter方法 public class RedissonConfig { private String host; private String port; private String password; @Bean public RedissonClient redissonClient() { // 1. 创建配置 Config config = new Config(); String redisAddress = String.format("redis://%s:%s", host, port); // 使用单个Redis,没有开集群 useClusterServers() 设置地址和使用库 config.useSingleServer().setAddress(redisAddress).setDatabase(3).setPassword(password); // 2. 创建实例 RedissonClient redisson = Redisson.create(config); return redisson; } }
- 新建RedissonConfig类,配置Redis连接信息
- 使用Redisson
- 在xxxService类中注入RedissonClient,并使用Redisson提供的分布式锁, 以定时任务为例:
@Component @Slf4j public class PreCacheJob { @Resource private UserService userService; @Resource private RedisTemplate<String, Object> redisTemplate; @Resource private RedissonClient redissonClient; // 重点用户 private List<Long> mainUserList = Arrays.asList(1L); // 每天执行,预热推荐用户 @Scheduled(cron = "0 59 23 * * *") //自己设置时间测试 public void doCacheRecommendUser() { RLock rlock = redissonClient.getLock("hjx:precachejob:docache:lock"); try { if (rlock.tryLock(0, 30000L, TimeUnit.MILLISECONDS)) { //查数据库 for (Long userId : mainUserList) { QueryWrapper<User> queryWrapper = new QueryWrapper<>(); Page<User> userPage = userService.page(new Page<>(1, 20), queryWrapper); String redisKey = String.format("hjx:user:recommend:%s", userId); ValueOperations valueOperations = redisTemplate.opsForValue(); //写缓存,30s过期 try { valueOperations.set(redisKey, userPage, 30000, TimeUnit.MILLISECONDS); } catch (Exception e) { log.error("redis set key error", e); } } } } catch (InterruptedException e) { log.error("doCacheRecommendUser, redis lock error", e); } finally { // 只能释放自己的锁 if (rlock.isHeldByCurrentThread()) { rlock.unlock(); } } } }
- 在xxxService类中注入RedissonClient,并使用Redisson提供的分布式锁, 以定时任务为例:
- 续期 (看门狗)
- Redisson提供了Watchdog来监控Redis的运行状态,如果Redis出现故障,Watchdog会自动释放锁,避免死锁。
- 原理: 监听当前线程, 默认过期时间是 30 秒, 每 10 秒续期一次 (补到 30 秒)
- 注意: 如果线程挂掉(注意 debug 模式也会被它当成服务器宕机),则不会续期
- 代码测试:
@Test void testWatchDog() { RLock lock = redissonClient.getLock("hjx:precachejob:docache:lock"); try { // 只有一个线程能获取到锁 if (lock.tryLock(0, -1, TimeUnit.MILLISECONDS)) { Thread.sleep(300000);//todo 实际要执行的代码 System.out.println("getLock: " + Thread.currentThread().getId()); } } catch (InterruptedException e) { System.out.println(e.getMessage()); } finally { // 只能释放自己的锁 if (lock.isHeldByCurrentThread()) { System.out.println("unLock: " + Thread.currentThread().getId()); lock.unlock(); } } }