Runnable 实例中的 ExecutorService awaitTermination 关闭信号

ExecutorService awaitTermination shutdown signal in the Runnable instance

我有几个关于 ExecutorService 和关闭过程的问题。 我的用例: 我使用 ExecutorService 生成固定数量的线程,其 运行 方法如下所示:

while (true) {
   try {
      this.currentThreadRunning = true;
      processMessage();
   }
   catch (Throwable e) {
      // Keeping the thread alive despite exceptions.
   }
}

这些线程 运行 无限,轮询消息。

我想做什么? 我正在为消息轮询 SQS 队列并处理它们。

显然,在我的例子中,ExecutorService's 关闭方法不起作用。当 shutdownNow() 被调用时,我所有的线程都被毫不客气地关闭了。我恨它!

有没有办法在我的 Runnable 实例中(在 finally 块中?)调用 awaitTermination 并验证是否已启动关闭并为当前线程触发相同的关闭?

更新:我重构了我的代码以执行轮询,然后生成线程来处理它们。因此,Runnable 实例的 运行 方法不必是无限循环。 awaiTermination 将导致线程的明确关闭。可以肯定的是,我在 awaitTermination.

之后触发了 shutdownNow

对于无限 运行 Runnables 我依赖于捕获一个 InterruptedException,它通常会从我的调用 shutdownNow() 或偶尔从调用 Future#cancel(true) 中抛出

while(!Thread.interrupted()) {
    try {

    } catch(InterruptedException e) {
        break;
    } catch(Throwable e) {
        // Keeping the thread alive despite exception
    }
}
// Thread was interrupted via shutdownNow(), cleanup resources

如果我需要区分可恢复中断和关闭中断,那么我在我的 Runnables 中共享一个 AtomicBoolean doShutdown,它被初始化为 false 并设置为 true 如果我想要一个 InterruptedException 来终止线程。

您必须检查您 运行 所在的线程的中断状态(请参阅此处的中断教程:https://docs.oracle.com/javase/tutorial/essential/concurrency/interrupt.html)。您的代码应该是:

while (!Thread.currentThread().isInterrupted()) {
        try {
            this.currentThreadRunning = true;
            processMessage();
        }
        catch (Throwable e) {
            // Keeping the thread alive despite exceptions.
        }
}

但是请注意,您必须在从可运行对象调用的代码中正确处理中断。如果有类似下面的内容:

try {
    // do something
} catch(InterruptedException e) {
    // ignore
}

那这就不行了。处理 InterruptedException 的正确方法是调用 Thread.currentThread().interrupt();.

我认为你所做的在概念上是错误的。

awaitTermination的意思是等待所有线程自然结束,然后停止执行器。提交 Runnable 时,它不应该知道它的执行上下文,因此,恕我直言,将你的可运行对象与你的执行程序耦合并不是一个好主意。

也许您应该查看 Future class 并将您的 Runnable 实施移到那里。然后你将被迫实施一个你可能会觉得有用的 cancel(boolean) 方法。

您的具体用例是什么?也许如果你解释一下,社区可以指出一个更合适的实现。

你不应该调用 shutdownNow() 但你应该只调用 shutdown 并使用 awaitTermination 等待一段时间。

所以关机会是这样的

声明一个可变变量

private volatile stopThread = false;

关机时你打电话

 this.stopThread = true;
 executor.shutdown();
 executor.awaitTermination(..
 executor.shutdownNow() // in case termination takes too long

然后在线程中检查 stopThread 变量。你不能在这里使用 isInterrupted 因为我们没有中断线程。我们只是在等待线程基于此条件退出

if(stopThread){
 // calling off all the operations and returning 
}

我写过一篇关于正确关闭executorservice的文章 http://programtalk.com/java/executorservice-not-shutting-down/ 希望对您有所帮助。