我已经阅读并重新阅读了Java Concurrency in Practice,我已经阅读了几篇关于这个主题的主题,我已经阅读了IBM文章Dealing with InterruptedException但是有些东西我根本没有理解我认为可以分为两个问题:
如果我自己从未打断过其他线程,那么什么可以触发 InterruptedException ?
如果我从未使用 interrupt()打断其他线程(比如因为我正在使用其他方法来取消我的工作线程,比如毒丸和 (!取消)样式循环[正如在JCIP中解释的那样]),那么 InterruptedException 是什么意思?抓到一个我该怎么办?关闭我的应用程序?
答案 0 :(得分:47)
线程中断机制是让(协作)线程响应请求以停止正在执行的操作的首选方法。任何线程(包括我认为的线程本身)都可以在线程上调用interrupt()
。
在实践中,interrupt()
的正常用例涉及某种框架或管理器,告诉某些工作线程停止他们正在做的事情。如果工作线程是“中断感知”,它将注意到它已经通过异常中断,或者通过定期检查其中断标志。在注意到它被中断后,一个表现良好的线程会放弃它正在做的事情并结束自己。
假设使用上述用例,如果代码在Java框架或某个工作线程中运行,则可能会中断您的代码。当它被中断时,你的代码应该放弃它正在做的事情,并以最合适的方式使自己结束。根据代码的调用方式,可以通过返回或抛出一些适当的异常来完成。但它可能不应该调用System.exit()
。 (您的应用程序不一定知道它被中断的原因,并且它当然不知道是否还有其他线程需要被框架中断。)
另一方面,如果您的代码不是设计为在某个框架的控制下运行,您可能会认为InterruptedException
是一个意外的异常;即一个bug。在这种情况下,您应该像处理其他错误一样处理异常;例如将其包装在未经检查的异常中,并在处理其他意外未经检查的异常的同一点捕获并记录它。 (或者,您的应用程序可以简单地忽略中断并继续执行它正在执行的操作。)
1)如果我自己从未打断过其他线程,那么什么会触发InterruptedException?
一个示例是,如果使用Runnable
执行ExecutorService
个对象,则会在服务上调用shutdownNow()
。从理论上讲,任何第三方线程池或线程管理框架都可以合法地做这样的事情。
2)如果我从未使用interrupt()中断其他线程......那么
InterruptedException
是什么意思?抓到一个我该怎么办?关闭我的应用程序?
您需要分析代码库以确定interrupt()
调用的原因以及原因。一旦你弄明白了,你就可以找出>>你的<<应用程序的一部分需要做。
直到你知道为什么InterruptedException
被抛出,我建议把它当作一个难以理解的错误;例如将堆栈跟踪打印到日志文件并关闭应用程序。 (显然,这并不总是正确的答案......但关键是这是“一个bug”,需要引起开发人员/维护人员的注意。)
3)如何找出谁/什么叫
interrupt()
?
对此没有好的答案。我能建议的最好的方法是在Thread.interrupt()
上设置断点并查看调用堆栈。
答案 1 :(得分:12)
如果您决定将代码与其他库集成,则可以在代码上调用interrupt()
。例如如果您决定将来在ExecutorService内执行代码,那么可能会强制通过interrupt()
关闭代码。
简而言之,我不仅会考虑您的代码正在运行现在的位置,而是考虑将来可能运行的代码。例如你打算把它放在图书馆吗?一个容器?其他人将如何使用它?你打算重复使用吗?
答案 2 :(得分:9)
正如其他人所指出的那样,中断线程(实际上是打断阻塞呼叫)通常用于干净地退出或取消正在进行的活动。
但是,您不应将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();
}
答案 3 :(得分:3)
问题的问题是“我”。 “我”通常指的是一个类的单个实例。我的意思是,任何特定的低级代码(类)都不应该依赖于整个系统的实现。说过你确实做了一些“架构”决定(比如运行什么平台)。
来自JRE的可能意外中断是java.util.concurrent
中已取消的任务并关闭小程序。
线程中断的处理通常写得不正确。因此,我建议在可能的情况下避免引起中断的架构决策。但是,应始终正确写入代码处理中断。现在无法从平台中取出中断。
答案 4 :(得分:2)
您可以通过创建自己的线程类(扩展java.lang.Thread
)和覆盖interrupt()
方法来学习这一点,在该方法中,您将堆栈跟踪记录到String字段中,然后转移到super。中断()。
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();
}
}
答案 5 :(得分:1)
如前所述,另一个库可以中断你的线程。即使库没有显式访问代码中的线程,它们仍然可以获取正在运行的线程列表,并使用以下method以这种方式中断它们。
答案 6 :(得分:0)
InterruptedException
表示例程可能被中断,但不一定会被中断。
如果您不期望中断,那么您应该将其视为任何其他意外异常。如果它处于关键部分,意外异常会产生令人发指的后果,最好尝试清理资源并优雅地关闭(因为获取中断信号表明正在使用不依赖于中断的精心设计的应用程序)在某种程度上它没有设计,因此必定有一些错误)。或者,如果所讨论的代码是非关键或微不足道的代码,您可能希望忽略(或记录)中断并继续运行。
答案 7 :(得分:0)
我想我理解为什么你对中断感到有些困惑。请仔细考虑我的答案:
如果我自己从未打断过其他线程,那么什么可以触发 InterruptedException ?
首先你可以打断其他线程;我知道在JCiP中提到你永远不应该打断你不拥有的线程;但是,必须正确理解这一陈述。这意味着你的代码可能在任意线程中运行不应该处理中断,因为它不是线程的所有者,它不知道它的中断策略。因此,您可以请求中断其他线程,但让其所有者采取中断行动;它有封装在其中的中断策略,而不是你的任务代码;至少要礼貌地设置中断标志!
有很多方法可能会出现中断,可能是超时,JVM中断等。
如果我从未使用interrupt()中断其他线程(比如因为我正在使用其他方法来取消我的工作线程,例如毒丸和while(!取消)样式循环[如JCIP中所述) ),InterruptedException是什么意思?抓到一个我该怎么办?关闭我的应用程序?
你需要在这里非常小心;如果您拥有引发InterruptedException(IE)的线程,那么您知道在捕获它时该怎么做,比如你可能会关闭你的应用程序/服务,或者你可以用一个新的替换这个被杀死的线程!但是,如果您没有拥有该线程,那么在捕获IE时要么将其重新抛出调用堆栈的更高位置,要么在执行某些操作之后(可能是日志记录),重置中断状态,以便拥有此线程的代码在控制到达时,可以了解线程被中断并因此采取行动,因为它只知道中断策略。
希望这会有所帮助。