单线程执行者无声地丢弃任务
  我正在努力解决一个问题,在一天中的大部分时间工作顺利之后,一个可调用的任务被放入一个Java单线程执行程序中,并且显然永远不会执行。  随后调用提交新任务失败, ExecutorService似乎已经死亡。  此时,生产任务的客户端将停止服务,直到流程可以重新启动,这在工作时间内是不可能的。 
  一些背景:多个高吞吐量生产者线程将他们的任务放到他们自己专用的Single Thread ExecutorService并立即返回。  低延迟对生产者线程非常重要。  生产者线程和执行程序线程之间有一对一的关系。  需要为每个生产者线程处理任务。  任务可以在执行程序线程中排队等待,只要需要执行即可。  交通是突发性的,所以消费者总是赶上他们的生产者。 
JDK:RedHat Linux上的jdk1.8.0_92
我定义了我的Executor服务:
 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后续call from Executor也没有例外。 
  可调用任务从未执行的原因是因为inboundMsgSender Single Thread ExecutorService中的inboundMsgSender Single Thread ExecutorService被阻塞,正在等待来自先前调用的`doExpensiveLogic(消息)内的FutureTask.get() 。 
这里的教训是,我认为ExecutorService的线程在被阻塞时正在死亡。 线程死亡由ExecutorService处理,所以我等待问题再次发生,并使用JStack进行线程转储。 线程转储显示了执行程序服务线程被阻止的位置。
"pool-54-thread-1" #354 prio=5 os_prio=0 tid=0x567c3c00 nid=0xae4a waiting on condition [0x51125000]
   java.lang.Thread.State: WAITING (parking)
    at sun.misc.Unsafe.park(Native Method)
    - parking to wait for  <0x69458368> (a com.aqua.api.SequentialExecutorService$ClientTaskHandle)
    at java.util.concurrent.locks.LockSupport.park(LockSupport.java:175)
    at java.util.concurrent.FutureTask.awaitDone(FutureTask.java:429)
    at java.util.concurrent.FutureTask.get(FutureTask.java:191)
    at com.aqua.jms.multiserver.impl.MultiServerJmsConnection.isConsumerConfigured(MultiServerJmsConnection.java:301)
    at com.aqua.jms.multiserver.migration.MigrationConnectionWrapper.getAdministrationConnection(MigrationConnectionWrapper.java:152)
当它再次发生时我采取的步骤:
您可以清楚地从堆栈跟踪中看到线程在FutureTask.get()上处于活动状态和等待状态,因此需要完成的任务就是修复Future Task或重构逻辑,并使其可用于我的线程直接打电话。
链接地址: http://www.djcxy.com/p/50189.html