一、现象
java项目中,在启动时会自动开启一个线程去redis中循环读取标识是否有任务需要执行,有一天线上突然出现异常,并且也没有找到相关的异常日志,排查发现是这个线程没有正常执行,后来经过日志仔细排查,发现redis曾出现过异常,服务端日志中找到Could not get a resource from the pool,只出现了2分钟,后redis又正常了,经过观察也是出现这个异常后,线程就不能正常执行了。
二、解决
在循环代码中加入try..catch进行异常捕获,避免出现异常线程停止执行。优化后的伪代码如下。
@PostConstruct
public void task(){
//另起线程执行,避免阻塞无法启动
ExecutorService executorService = Executors.newFixedThreadPool(1);
executorService.submit(()->{
while (true){
try {
//循环读取redis中是否有待执行任务
Set<Object> taskSet = RedisUtil.redisTemplate.opsForZSet().rangeByScore(taskName,0,System.currentTimeMillis(),0,1);
if(taskSet==null||taskSet.isEmpty()){
//休眠5秒后再次执行
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
logger.error("task thread sleep error",e);
}
continue;
}
//发送kafka异步消费处理
Object it = taskSet.iterator().next();
//删除成功
if(RedisUtil.redisTemplate.opsForZSet().remove(delayQueueName,it)>0){
//执行业务代码
}
} catch (Exception e) {
try {
//如果出现异常,线程睡眠5秒
Thread.sleep(5000);
} catch (InterruptedException ex) {
logger.error("task thread sleep error",ex);
}
logger.error("task exec error",e);
}
}
});
}