一、 简介
上篇文章介绍了使用自定义注解和AOP来实现方法加锁解决并发问题,经过测试发现了一些问题,基于RedisLockRegistry无法自动续期。
情景:当线程A进入方法获取锁,执行方法超过了RedisLockRegistry设置的超时时间,锁自动释放,此时排队的线程B进行方法获取锁,线程A执行完后将线程B的锁释放,该问题的原因在于没有对锁自动续期。
二、解决方法
引入redisson依赖
<!--使用redisson作为分布式锁-->
<dependency>
<groupId>org.redisson</groupId>
<artifactId>redisson</artifactId>
<version>3.16.8</version>
</dependency>
对redisson进行配置,注意,此处是redisson的单机模式,如果是redis集群还需要特别处理,此处暂不说明
import org.redisson.Redisson;
import org.redisson.api.RedissonClient;
import org.redisson.config.Config;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class MyRedissonConfig {
@Value("${spring.redis.host}")
private String redisHost;
@Value("${spring.redis.port}")
private String redisPort;
@Value("${spring.redis.password}")
private String redisPassWord;
/**
* 所有对Redisson的使用都是通过RedissonClient对象
* 集群模式的话还需要特别配置yml文件
* @return
*/
@Bean(destroyMethod = "shutdown")
public RedissonClient redissonClient(){
// 创建配置 指定redis地址及节点信息
Config config = new Config();
config.useSingleServer().setAddress("redis://"+redisHost+":"+redisPort).setPassword(redisPassWord);
// 根据config创建出RedissonClient实例
RedissonClient redissonClient = Redisson.create(config);
return redissonClient;
}
}
修改LockAspect切面,将RedisLockRegistry替换为redisson
@Autowired
private RedissonClient redissonClient;
RLock lock = redissonClient.getLock(lockName);
lock.lock();
try {
log.info("获取redis锁");
Object result = joinPoint.proceed();
return result;
} catch (Throwable e) {
log.error("redis加锁方法{}执行异常:{}", methodDict, e);
throw new RuntimeException(e.getMessage());
} finally {
log.info("释放redis锁");
try{
lock.unlock();
}catch (Exception e){
log.warn("释放锁失败:{}",e);
throw new RuntimeException(e.getMessage());
}
}
注意同样需要在finally 中对锁进行释放