【问题标题】:Cleanly Stopping a Thread干净地停止线程
【发布时间】:2012-12-07 14:57:20
【问题描述】:

我终于设法在我的程序中实现了 Thread.interrupt() 而不是 Thread.stop()。但是我不确定我是否做得很好。

我有一个类,它扩展了 Thread 并声明了几个方法。 EVERY 方法已经抛出 InterruptedException(每个方法执行 I/O 密集型操作,其中一些需要几分钟才能完成,因此我没有使用线程安全标志,因为标志不会得到检查直到操作完成后)。我还在这些方法中的几个地方添加了以下代码来引发异常:

if (this.isInterrupted()) throw new InterruptedException();

在 run() 方法中,我为 InterruptedException 执行 try/catch 中的所有方法。如果被捕获,我会为我的类变量执行 Process.destroy() 和 BufferedReader.close()。

这一切都有效,而且似乎效果很好,但是我有几个问题:

  1. 10个以上的方法都抛出InterruptedException是否正确?有没有更好的方法来做到这一点?
  2. 通过检查 isInterrupted() 来膨胀方法是否正确?
  3. 在 catch InterruptedException 块结束时,我是否必须执行“返回”或“空”某些值以使线程可用于 GC?如果我重新创建线程,初始化时间会比平时长。
  4. 最后,是否有任何与我所做的相关的问题/改进?

提前感谢您的帮助!

【问题讨论】:

  • 最干净和最简单的方法是拥有一个(线程安全)标志,您可以在线程本身中切换。使用 interrupt() 通常由非常健壮的应用程序使用,以避免许多可能的陷阱。
  • @Skynorth 谢谢,也许值得一提的是这些方法执行 IO 密集型操作,并且在这些操作(有时需要 2 分钟以上)完成之前不会检查标志。
  • 我不认为你真的想知道“正确”(Q's 1&2);这是编译器的问题,它是否在所有合理情况下都按照您的预期运行,我们已经(可能)从您的描述中知道。
  • @DonalFellows 也许正确不是正确的词,他们可以改进吗?

标签: java multithreading


【解决方案1】:

Java 中的线程中断并不意味着停止该线程的执行。不是停止,而是中断。当一些基本和关键的事情发生变化时,线程可以被中断,告诉线程它的执行上下文、它的任务或它的环境以某种重要的方式发生了变化。对此消息的线程反应是特定于实现的。它可以是停止,可以是重新启动或任何其他动作。不处理中断的线程不能被中断,但它的行为仍然可以改变,例如,通过使用共享变量。

例如,假设您有许多线程,所有线程都在问题空间的一部分中搜索解决方案。当一个线程找到解决方案时,它可以中断其他线程,因为它们对解决方案的搜索不再相关。已经找到了解决办法。

或者想象一个连续工作的主线程和一个网络通信线程。每次网络线程接收到消息时,它中断带有消息的工作线程。基于消息和上下文是什么,工作线程可以决定下一步做什么。例如,如果消息是“STOP”,那么它可以立即停止所有执行。如果消息是“RESET”,它可以从头开始,或者可能不从头开始,并根据执行上下文重用以前的一些工作。

10多个方法,全部抛出 InterruptedException?有没有更好的方法来做到这一点?

不,这很好,只要您知道自己在做什么。如果您实现中断只是为了停止线程,则无需抛出 InterruptedExceptions。线程的 run() 方法是它的第一个方法,并且异常不会进一步进入堆栈。

通过检查 isInterrupted() 来膨胀方法是否正确?

取决于上下文。检查通常会在一些关键代码之前添加。通常它作为循环块中的第一项添加。

在 catch InterruptedException 块的末尾,我必须执行一个 'return' 或 'null' 某些值以使线程可用于 GC?如果我重新创建线程它需要比平时更长的时间 初始化。

没有。一旦线程从 run() 方法中存在,它就任由 GC 摆布。共享变量不会被 GC,只要它们仍然被其他对象引用。

【讨论】:

  • 很好且内容丰富的答案,谢谢。但是,当您说“线程的 run() 方法是第一个,并且异常不会再往回走”时,我不明白。我找不到一种方法来检测 run() 块中的线程中断而不使方法抛出异常。我的目标是停止线程。再次感谢您的详细回复!
  • 每次创建线程时,都会从它的run() 方法开始执行(除了由JVM 创建的主线程,它以main() 方法开始)。那是堆栈的顶部,如果在 run() 方法中抛出异常,则无法在堆栈的任何位置捕获它。 run() 方法位于栈顶。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-11-25
  • 2011-04-07
  • 2010-10-26
  • 2014-03-29
相关资源
最近更新 更多