现象
功能:定时任务,每半个小时就执行一次。
现象:在某一天停止触发了。
CheckAutoDeployJob.java
/**
* 每小时的30分,零秒触发
*/
@Scheduled(cron = "0 30 * * * ?")
public void work() {
// todo
logger.info("触发自动续期检查:===" + new Date());
...
}
排查过程
线上机器日志排查
grep "触发自动续期检查" /opt/ione/logs/ione-info.log
日志分析
- 2020-06-11 20:30:00这个时间后,就没有触发了。
- 检查其他定时任务是否正常运行。(这个考虑后续证明无需验证)
- 查看所有线上其他机器是否也卡在了这个时间。(其他机器的定时任务卡主的时间点不一样)
线上的jstack日志排查
> jps
435 spring.jar
> jstack -l 435 > jstack_20200618.out
> grep 'CheckAutoDeployJob' jstack_20200618.out
...
at java.util.concurrent.CountDownLatch.await(CountDownLatch.java:231)
at com.bj58.rdm.web.service.env.EnvConfigService.doDeploy(EnvConfigService.java:190)
at com.bj58.rdm.web.service.job.BaseJob.doDeploy(BaseJob.java:134)
at com.bj58.rdm.web.service.job.CheckAutoDeployJob.lambda$triggerAutoDeploy$23(CheckAutoDeployJob.java:72)
at com.bj58.rdm.web.service.job.CheckAutoDeployJob$$Lambda$572/1203642436.accept(Unknown Source)
...
结合代码
查找EnvConfigService-doDeploy方法
CountDownLatch countDownLatch = new CountDownLatch(n);
for (...) {
...
countDownLatch.countDown();
}
countDownLatch.await();
这样,问题就已经定位了。
解决方案
分析原因
countDownLatch.await()会将当前线程持续waiting导致线程一直处于waiting on condition的条件下。
解决方案
countDownLatch.await()因为要一直等待。
使用方式,多线程如果无法countDown。
临时方案:
// 设置countDownLatch默认10分钟超时
countDownLatch.await(10, TimeUnit.MINUTES);
最终方案还是要定位countDown为何不生效的原因。以上只是让程序能做个兼容处理。
解决后的验证
思考
countdownlatch的使用场景
有一个任务想要往下执行,但必须要等到其他的任务执行完毕后才可以继续往下执行的。
多线程的顺序执行的方式
个人使用方式和偏好。future和callable组合。代码好理解,异常可捕捉和抛出。
关于其他的方式,待仔细研究后再定论了。