首页 文章

单线程执行程序静默删除任务

提问于
浏览
2

我正在努力解决一个问题,即在一天的大部分时间里顺利工作之后,一个可调用的任务被放入Java单线程 Actuator 中,显然永远不会被执行 . 提交新任务的后续调用失败, 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调用callable:

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 且没有例外 .

1 回答

  • 0

    永远不执行可调用任务的原因是因为 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)
    

    我再次发生的步骤:

    • 标识执行程序服务的单线程的线程名称 .

    • 在linux上,识别进程的PID .

    • 使用jstack进行PID $ jstack 33516> threaddump.txt的线程转储

    • 在线程转储中搜索线程名称(参见上文) .

    您可以从堆栈跟踪中清楚地看到线程是在FutureTask.get()上的LIVE和WAITING,所以需要做的就是修复Future Task或重构逻辑并使其可用于我的线程直接打电话 .

相关问题