【发布时间】:2017-07-03 08:06:16
【问题描述】:
我正在努力解决一个问题,在一天的大部分时间里顺利工作之后,一个可调用的任务被放入 Java 单线程执行器中,并且显然永远不会被执行。提交新任务的后续调用失败,ExecutorService 似乎已死。此时,产生任务的客户端停止服务,直到可以重新启动流程,这在工作时间是不可能的。
一些背景:
多个高吞吐量生产者线程将他们的任务放在他们自己专用的Single Thread ExecutorService 上并立即返回。低延迟对于生产者线程非常重要。生产者线程和执行者线程之间存在一对一的关系。需要按顺序为每个生产者线程处理任务。任务可以在执行器线程中排队,只要它们需要执行就可以。流量是突发的,所以消费者总是赶上他们的生产者。
JDK:RedHat Linux 上的 jdk1.8.0_92
我定义了我的执行器服务:
private final ExecutorService inboundMsgSender = Executors.newSingleThreadExecutor();
生产者线程调用回调:
public void onMessageFromFix(MessageEvent event, final Message message) {
log.info("submit to Executor: " + message.toString());
inboundMsgSender.submit(new Callable<Void>() {
public Void call() {
try {
onMessageFromExecutor(event, message);
} catch (Throwable e) {
log.error("error", e);
}
return null;
}
});
}
ExecutorService 调用可调用对象:
public void onMessageFromExecutor(MessageEvent event, final Message message) {
try {
log.info("call from Executor: " + message.toString());
doExpensiveLogic(message);
} catch (Exception e) {
log.error("error", e);
}
}
正常情况下我在日志文件中看到:
submit to Executor: 4928
call from Executor: 4928
这就是我知道 Executor 线程正在运行 Callable 的方式。
当问题发生时,我只看到以下内容:
submit to Executor: 4928
没有后续的call from Executor,也没有异常。
【问题讨论】:
-
尝试在尝试之前、onMess 之后放置日志消息...这将缩小搜索范围
-
什么调用 onMessageFromFix? inboundMsgSender.submit 是否有可能抛出调用者正在吞下的异常?
-
调用由第三方 API 调用。是的,有可能正在吞噬一个异常。我认为这是最可能的原因。我想将 Callable 更改为 Runnable,因为我等不及 get() 重新抛出任何异常。我听说使用 Runnable 会在我的 try/catch 中捕获异常,但我不确定。
-
如果您认为这是最可能的原因,那么在提交时放置一个 try-catch,应该会告诉您。我认为如果您使用 runnable 或 callable 并没有太大区别,但我认为在您的情况下,runnable 更干净一些,因为您既没有返回结果也没有抛出检查的异常。
-
迈克尔,也抓住 Throwable。
标签: java multithreading