- 加锁+过期时间必须是一个原子性操作,如果锁已经加上了,在设置过期时间时程序断电,则会导致锁一直存在,利用setIfAbsent的Api中的加锁+过期时间解决该问题
- 删除锁也要是个原子操作,先查再删依然会出现以上情况,利用redis执行lua脚本解决删除锁问题
pom
<dependency>
<groupId>org.redisson</groupId>
<artifactId>redisson</artifactId>
<version>3.10.6</version>
</dependency>
加锁
@Autowired
private OldMarketDataService oldMarketDataService;
@Autowired
private RedissonClient redissonClient;
@Resource
private MsHistoryCodeMapper msHistoryCodeMapper;
public static final String MS_HISTORY = "MS_HISTORY";
public static final ThreadPoolExecutor POOL = new ThreadPoolExecutor(
1,
1,
60,
TimeUnit.SECONDS,
new LinkedBlockingQueue<>(1),
Executors.defaultThreadFactory(),
new ThreadPoolExecutor.DiscardPolicy()
);
@Override
public void syncOld() {
POOL.execute(() -> {
RLock lock = redissonClient.getLock(MS_HISTORY);
try {
boolean isLock = lock.tryLock(10, TimeUnit.MINUTES);
if (isLock) {
msHistoryCodeMapper.updateDealStatus1();
List<MsHistoryCodePO> msHistoryCodePoList = msHistoryCodeMapper.queryListByStatus1();
if (CollectionUtils.isEmpty(msHistoryCodePoList)) {
return;
}
msHistoryCodePoList.forEach(msHistoryCodePo -> {
oldMarketDataService.syncOldByMarket(msHistoryCodePo.getMarketId());
msHistoryCodeMapper.updateStatusById(msHistoryCodePo.getId(), 2);
});
}
} catch (Exception e) {
log.error("异常日志", e);
} finally {
if (lock.isLocked() && lock.isHeldByCurrentThread()) {
lock.unlock();
}
}
});
}
redis配置类
/**
* redis配置
*
* @author XLJ
* @date 2020/12/28 16:24
*/
@Configuration
public class RedisConfig {
@Value("${spring.redis.cluster.nodes}")
private String nodes;
@Value("${spring.redis.password}")
private String password;
@Bean
public RedissonClient redissonClient() {
if (StringUtils.isBlank(nodes)) {
throw new RuntimeException("nodes can not be empty!");
}
String address = "redis://%s";
String[] split = nodes.split(",");
String[] array = new String[split.length];
for (int i = 0; i < split.length; i++) {
String format = String.format(address, split[i]);
array[i] = format;
}
Config config = new Config();
config.useClusterServers().addNodeAddress(array).setPassword(password);
return Redisson.create(config);
}
}
项目重启清除锁
/**
* 项目重启后清除redis锁
*
* @author xlj
* @date 2021/1/12
*/
@Component
@Slf4j
public class RedisInit implements ApplicationContextAware {
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
RedissonClient bean = applicationContext.getBean(RedissonClient.class);
bean.getKeys().delete(MrkHistoryScheduleTaskServiceImpl.MS_HISTORY);
log.info("清除Redis中的主站行情历史数据锁 --> {}", MrkHistoryScheduleTaskServiceImpl.MS_HISTORY);
}
}