如果我不在,谁在调用Java线程中断()方法?
我已经阅读并重新阅读了Java Concurrency in Practice,我已经阅读了关于这个主题的几个主题,我已经阅读了IBM 处理InterruptedException的文章,但是还有一些东西我根本不知道我认为可以被破坏分成两个问题:
-
如果我从来没有中断其他线程,什么可以触发InterruptedException ?
-
如果我永远不会用interrupt()自己中断其他线程(也就是说,因为我正在使用其他方法来取消我的工作线程,比如毒丸和while(!取消)样式循环[都在JCIP中解释过]), InterruptedException然后意味着什么? 抓到一个,我该怎么办? closures我的应用程序?
线程中断机制是获取(协作)线程响应请求以停止正在执行的操作的首选方式。 任何线程(包括线程本身,我认为)可以调用线程interrupt()
。
在实践中, interrupt()
的正常使用情况涉及某种框架或pipe理者告诉一些工作者线程停止他们正在做的事情。 如果工作线程是“中断感知”,它会注意到它已经被exception中断,或者定期检查中断标志。 在注意到它被打断后,一个行为正常的线程会放弃正在做的事情并结束自己。
假设上面的用例,如果代码在Java框架或某个工作线程中运行,您的代码可能会被中断。 当它被打断时,你的代码应该放弃它正在做的事情,并以最恰当的方式结束自己。 根据你的代码被调用的方式,这可以通过返回或通过抛出一些适当的exception来完成。 但它可能不应该调用System.exit()
。 (你的应用程序不一定知道为什么会被中断,而且它肯定不知道是否还有其他线程需要被框架中断。)
另一方面,如果你的代码不是被devise成在一些框架的控制下运行的,你可能会认为InterruptedException
是一个意外的exception; 即一个错误。 在这种情况下,您应该像处理其他错误一样对待exception。 例如,将其包装在一个未经检查的exception中,并在与其他意外的未经检查的exception处理的同一点捕获并logging它。 (或者,您的应用程序可以简单地忽略中断并继续执行它所做的事情。)
1)如果我从来没有中断其他线程,可以触发InterruptedException?
一个例子是如果您的Runnable
对象是使用ExecutorService
并且在服务上调用了shutdownNow()
。 理论上讲,任何第三方线程池或线程pipe理框架都可以合法地做到这一点。
2)如果我永远不会中断其他线程我自己使用中断()…
InterruptedException
然后意味着什么? 抓到一个,我该怎么办? closures我的应用程序?
您需要分析代码库来确定什么是interrupt()
调用以及为什么。 一旦你明白了,你可以计算出你的应用程序需要做什么。
直到你知道为什么InterruptedException
被抛出,我会build议把它视为一个硬性错误; 例如打印堆栈跟踪到日志文件并closures应用程序。 (很显然,这并不总是正确的答案,但重要的是这是一个“错误”,需要引起开发者/维护者的注意。)
3)如何找出谁调用了
interrupt()
?
没有好的答案。 我可以build议的最好的方法是在Thread.interrupt()
上设置断点并查看调用堆栈。
如果您决定将您的代码与其他库集成,则可以在代码上调用interrupt()
。 例如,如果您决定将来在ExecutorService中执行代码,那么可能会通过interrupt()
强制closures。
简而言之,我不仅要考虑你的代码现在在哪里运行,而且还要考虑它将来可能运行的环境。 你打算把它放在图书馆里吗? 一个容器? 其他人将如何使用它? 你打算重用吗?
正如其他人已经指出的,中断一个线程(实际上,中断阻塞呼叫)通常用于干净地退出或取消正在进行的活动。
但是,你不应该把一个InterruptedException
作为一个“退出命令”。 相反,您应该将中断视为控制线程运行状态的一种手段,就像Object.notify()
一样。 从调用Object.wait()
唤醒之后(不要以为唤醒意味着你的等待条件已经满足),你可以用同样的方法检查当前状态,检查你为什么被打断。 通常有办法做到这一点。 例如, java.util.concurrent.FutureTask
有一个isCancelled()
方法。
代码示例:
public void run() { .... try { .... // Calls that may block. } catch (InterruptedException e) { if (!running) { // Add preferred synchronization here. return; // Explicit flag says we should stop running. } // We were interrupted, but the flag says we're still running. // It would be wrong to always exit here. The interrupt 'nudge' // could mean something completely different. For example, it // could be that the thread was blocking on a read from a particular // file, and now we should read from a different file. // Interrupt != quit (not necessarily). } .... } public void stop() { running = false; // Add preferred synchronization here. myThread.interrupt(); }
问题的问题是“我”。 “我”通常是指一个类的单个实例。 我的意思是,任何特定的低级代码(类)不应该依赖于整个系统的实现。 话虽如此,你确实做了一些“架构”的决定(比如运行什么平台)。
来自JRE的可能的意外中断在java.util.concurrent
被取消,并closuresapplet。
线程中断的处理通常是不正确的。 因此,我build议在可能的情况下避免造成中断的架构决定。 但是,代码处理中断应该始终正确写入。 现在不能从中断平台。
你可以通过创build你自己的线程类(扩展java.lang.Thread
)和重载的interrupt()
方法来学习这个,在这个方法中你将栈跟踪logging到一个string字段中,然后转移到super.interrupt()。
public class MyThread extends Thread { public volatile String interruptStacktrace; // Temporary field for debugging purpose. @Override public void interrupt() { interruptStacktrace = dumpStack(); // You implement it somehow... super.interrupt(); } }
如前所述,另一个库可能会中断你的线程。 即使库没有明确的访问你的代码中的线程,他们仍然可以通过下面的方法获得正在运行的线程列表并以这种方式中断它们。
InterruptedException
说,一个例程可能被中断,但不一定会。
如果你不希望中断,那么你应该把它当作你可能的任何其他意外的exception。 如果发生意外的exception会导致严重的后果,那么最好尝试清理资源并正常closures(因为获取中断信号表明您的devise良好的不依赖于中断的应用程序正在被使用在某种程度上它没有被devise,所以一定是有错的)。 或者,如果有问题的代码是非关键或微不足道的,那么您可能需要忽略(或logging)中断并继续。
我想我明白你为什么对中断感到困惑。 请考虑我的答案:
如果我从来没有中断其他线程,什么可以触发InterruptedException ?
首先你可能会打断其他线程; 我知道在JCiP中提到你不应该中断你不拥有的线程, 但是,这个陈述必须得到适当的理解。 这意味着你的代码可能在任意线程中运行,不应该处理中断,因为它不是线程的所有者,它不知道中断策略。 所以你可以要求中断其他线程,但让它的主人采取中断行动的过程; 它有封装在其中的中断策略,而不是你的任务代码; 至less要有礼貌地设置中断标志!
为什么仍然会有中断,可能是超时,JVM中断等等。
如果我永远不会用interrupt()自己中断其他线程(也就是说,因为我正在使用其他方法来取消我的工作线程,比如毒丸和while(!取消)样式循环[都在JCIP中解释过]), InterruptedException然后意味着什么? 抓到一个,我该怎么办? closures我的应用程序?
这里你要非常小心, 如果你拥有抛出InterruptedException(IE)的线程,那么你知道该怎么做,说你可能会closures你的应用程序/服务,或者你可以用一个新的replace这个死的线程! 然而,如果你不拥有这个线程,那么在捕获IE时要么重新抛出IE,要么在调用堆栈的上方重新抛出,或者在做了某些事情(可能是日志logging)之后,重置被中断的状态,以便拥有该线程的代码在控制达到时了解到线程被中断,因此只要知道中断策略就会采取行动。
希望这有助于。