ScheduledExecutorService 不执行原因排查
最近调整了一下项目定时获取 etcd 配置的代码,本地测试没有问题,但是有的项目部署就是不运行,也不报错
了解了一下 ScheduledExecutorService 在抛出异常后会停止运行,于是我从这个地方找起
首先我调整了一下定时任务执行代码
schedule.scheduleAtFixedRate(new Runnable() {
public void run() {
try {
refresh();
log.info("etcd config refresh successfully");
// 原
// } catch (Exception e) {
// 新
} catch (Throwable e) {
log.error("etcd config refresh failure", e);
}
}
}, TIME_CYCLE, TIME_CYCLE, TimeUnit.MILLISECONDS);
在有问题的机器上部署后,出现报错了,之前日志、控制台都没有报错,因为 NoSuchMethodError 继承自 Error,而我 catch 了 Exception,导致没有 catch 到,自动化的代码还是 catch Throwable 最好
NoSuchMethodError ConcurrentHashMap$KeySetView
[ERROR] [19:45:59] pool-4-thread-1 com.config.EtcdConfigService - etcd config refresh failure
java.lang.NoSuchMethodError: com.config.GeneralConfigGroup.keySet()Ljava/util/concurrent/ConcurrentHashMap$KeySetView;
at com.config.GeneralConfigGroup.putAll(GeneralConfigGroup.java:27)
at com.config.etcd.EtcdConfigGroup.loadNodeData(EtcdConfigGroup.java:92)
at com.config.EtcdConfigService.refresh(EtcdConfigService.java:132)
at com.config.EtcdConfigService$1.run(EtcdConfigService.java:109)
at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:471)
at java.util.concurrent.FutureTask.runAndReset(FutureTask.java:304)
at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.access$301(ScheduledThreadPoolExecutor.java:178)
at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run(ScheduledThreadPoolExecutor.java:293)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1145)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:615)
at java.lang.Thread.run(Thread.java:744)
网上找了一下,发现这个问题是因为高版本的 jdk 编译的字节码在 低版本 jdk 上运行导致的,但是我看了下配置,pom.xml 里面的 jdk 版本是正确的 1.7,虽然我用的是 1.8。
看源码可以知道,jdk7 和 jdk8 对 keySet 的实现是不一样的,这也就是异常的原因了,和报错信息是对的上的
![](https://img.haomeiwen.com/i8032592/2df1811e4af43998.png)
![](https://img.haomeiwen.com/i8032592/7b7bece4a99a71f5.png)
在这个老哥的帖子帮助下才知道,虽然语言级别设置的是 1.7 但是编译出的 class 并不能保证能在低版本jdk运行
Java高编译低运行错误(ConcurrentHashMap.keySet)
接下来,我把 jenkins 编译的 jdk 版本调整成了 jdk7,但是却报了另一个错误
![](https://img.haomeiwen.com/i8032592/9de43377a29d08c5.png)
原来 jenkins 支持的 jdk 最低版本是 jdk8,当我调整了编译 jdk 时,导致 jenkins 支持的代码也报错了
![](https://img.haomeiwen.com/i8032592/6b8af29c1568d316.png)
于是我重新建了一下任务,任务类型选择自由风格的软件项目,不要选 maven 项目(会涉及到 jenkins的支持代码),在新项目构建处 添加构建步骤 执行 shell,输入 mvn clean install,成功使用 jdk7 进行编译,ScheduledExecutorService etcd 刷新定时任务也成功执行了
![](https://img.haomeiwen.com/i8032592/74cc3fbc766ebd12.png)
在这里注意一下,可以指定 JAVA_HOME 变量,让 mvn 使用指定 jdk 进行编译,我们服务器上默认是 jdk7 就不需要配了
JAVA_HOME=/usr/local/jdk1.8.0_231
mvn -v
![](https://img.haomeiwen.com/i8032592/4ba9732870401449.png)