如何正确处理线程中断



我正在开发一个应用程序,该应用程序在某个时刻启动一个工作线程。这个线程的行为将根据用于启动它的参数而变化很大,但以下属性列表适用:

  • 它将执行一些小的I/O操作
  • 它将在第三方图书馆度过一小段时间
  • 它可能会为某个子任务创建一些工作线程(这些线程在任务完成后不会被重用)
  • 它将花费大部分时间处理数字(不存在阻塞调用)

由于可能的持续时间很长(5分钟到几个小时,具体取决于输入),我们希望能够中止计算。如果我们选择中止它,我们就不再关心输出,而且只要线程继续运行,它实际上就是在浪费宝贵的资源。由于代码在我们的控制之下,建议的方法是使用中断来指示中止。

虽然网络上的大多数例子都涉及在某个方法上循环的工作线程,但我的情况并非如此(这里有类似的问题)。在这个工作线程中也很少有阻塞调用,在这种情况下,本文建议手动检查中断标志。我的问题是:如何处理这个中断

我看到了几种选择,但无法决定哪种方法最"干净"。尽管我有一个实际的例子,但我主要对如何处理这个问题的"最佳实践"感兴趣。

  1. 抛出某种未检查的异常:这将以一种快速而简单的方式杀死线程,但它让我想起了不推荐使用的Thread#stop()方法所使用的ThreadDeath方法及其所有相关问题。我可以看到这种方法在拥有的代码中是可以接受的(由于已知的逻辑流),但在库代码中是不可接受的
  2. 抛出某种已检查的异常:这将以一种快速而简单的方式杀死线程,并通过强制程序员处理此事件来缓解类似ThreadDeath的问题。然而,它给代码带来了很大的负担,要求处处提及异常。并不是每件事都抛出InterruptedException是有原因的
  3. 退出具有"迄今为止最好的结果"或空结果的方法。由于涉及到大量的课程,这将是一项非常艰巨的任务。如果没有足够的注意,NullPointerExceptions可能会因空结果而出现,从而导致与第1点相同的问题。在大型代码库中几乎不可能找到这些原因

我建议您定期检查Thread.currentThread().isInterrupted(),如果设置了它,则可以安全地停止和停止。

您可以在一个方法中执行此操作,该方法检查此标志并抛出自定义的未检查异常或错误。

使用ExecutorService执行Runnable怎么样?签出可以指定超时的方法。例如

ExecutorService executor = Executors.newSingleThreadExecutor();
executor.invokeAll(Arrays.asList(new Task()), 10, TimeUnit.MINUTES); // Timeout of 10 minutes.
executor.shutdown();

在这里,Task当然实现了Runnable。

最新更新