如果不是,谁在调用Java Thread interrupt()方法?


87

我已经阅读并重新阅读了Java Concurrency in Practice,已经阅读了有关该主题的多个线程,已经阅读了IBM文章Dealing with InterruptedException,但是我根本不了解某些我认为可以打破的东西。分为两个问题:

  1. 如果我从来没有自己打过其他线程,什么会触发InterruptedException

  2. 如果我从不使用自己的interrupt()中断其他线程(例如,因为我正在使用其他方式取消工作线程,例如毒药和while(!cancelled)样式循环[如在JCIP中所述),那那么InterruptedException是什么意思?抓到我该怎么办?关闭我的应用程序?

Answers:


50

线程中断机制是获取(协作)线程以响应请求以停止其正在执行的操作的首选方法。任何线程(包括我认为的线程本身)都可以调用interrupt()Thread。

在实践中,通常的用例interrupt()涉及某种框架或管理器,该框架或管理器告诉某些工作线程停止其正在执行的操作。如果工作线程是“中断感知的”,它将注意到它已通过异常或通过定期检查其中断标志而被中断。注意到它已被中断后,行为良好的线程将放弃它正在执行的操作并自行终止。

假设上述用例,如果代码在Java框架中或从某些工作线程中运行,则代码可能会被中断。并且当它被中断时,您的代码应放弃正在执行的操作,并以最适当的方式使其自身结束。根据调用代码的方式,可以通过返回或引发一些适当的异常来完成此操作。但是它可能不应该调用System.exit()。(您的应用程序不一定知道为什么它被中断,并且它当然也不知道框架是否需要中断其他线程。)

另一方面,如果您的代码并非设计为在某些框架的控制下运行,则可以辩称,这InterruptedException是意外的异常;它可能会导致异常。即一个错误。在这种情况下,您应该像对待其他错误一样对待异常。例如,将其包装在未经检查的异常中,并在处理其他意外的未经检查的异常的同时捕获并记录下来。(或者,您的应用程序可以简单地忽略该中断,然后继续执行其操作。)


1)如果我从来没有自己打过其他线程,什么会触发InterruptedException?

一个示例是您的Runnable对象是否使用ExecutorServiceshutdownNow()在服务上调用。从理论上讲,任何第三方线程池或线程管理框架都可以合法地执行此类操作。

2)如果我从来没有使用过interrupt()自己打断其他线程...InterruptedException那么那意味着什么?抓到我该怎么办?关闭我的应用程序?

您需要分析代码库,以弄清楚进行interrupt()调用的原因以及原因。一旦弄清楚了,就可以确定应用程序>>您的<<部分需要做什么。

在您知道为什么InterruptedException会抛出该错误之前,我建议您将其视为硬错误;例如,将stacktrace打印到日志文件并关闭应用程序。(显然,这并不总是正确的答案……但是重点是,这是“错误”,需要引起开发人员/维护人员的注意。)

3)我怎么知道谁/打来interrupt()什么?

没有好的答案。我所建议的最好方法是在上设置一个断点Thread.interrupt()并查看调用堆栈。


12

如果您决定将代码与其他库集成,则它们可以调用interrupt()您的代码。例如,如果您将来决定在ExecutorService中执行代码,则可能会通过强制关闭interrupt()

简而言之,我不仅要考虑您的代码现在在哪里运行,而且还要考虑将来在什么情况下运行。例如,你要把它放进图书馆吗?一个容器?别人将如何使用它?您要重用它吗?


我以为只有shutdownNow才能调用interrupt()方法。关机也是如此吗?
Harinder

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

问题的问题是“我”。“ I”通常是指类的单个实例。我的意思是,任何特定的低级代码(类)都不应依赖于整个系统的实现。话虽如此,您确实已经做出了一些“架构”决策(例如要在哪个平台上运行)。

JRE中可能发生的意外中断是已取消的任务java.util.concurrent并关闭了applet。

线程中断的处理通常写不正确。因此,我建议在架构上做出决定,以尽可能避免造成中断。但是,代码处理中断应始终正确编写。现在无法将中断带出平台。


汤姆,您好,我记得您来自cljp的名字;)好吧,正是这样:我从来没有亲自抛出过interrupt() ...除非我捕获了InterruptedException并需要重新声明被中断的状态,但这仍然不是100%对我清楚。我是新来的,对赞扬和答案/评论(正确的和错误的)都感到惊讶:显然,这不是一个琐碎的主题,或者至少通常没有很好地解释。就是说,感谢所有帖子,我开始更清楚地了解正在发生的事情:)
SyntaxT3rr0r 2010年

3

您可以通过创建自己的线程类(Extending java.lang.Thread)和重写interrupt()方法来学习这一点,在该方法中,您将stacktrace记录到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();
    }
}

1

如前所述,另一个库可以中断您的线程。即使该库没有从您的代码中显式访问线程,它们仍然可以获取正在运行的线程列表,并使用以下方法以这种方式中断它们。


1

我想我理解您为什么对打扰有些困惑。请考虑以下答案:

如果我从来没有自己打过其他线程,什么会触发InterruptedException

首先,您可能会中断其他线程;我知道在JCiP中提到您永远不要中断您不拥有的线程。但是,此声明必须正确理解。这意味着可能在任意线程中运行的代码不应处理中断,因为由于它不是线程的所有者,因此不知道其中断策略。因此,您可以在其他线程上请求中断,但让其所有者执行中断操作的过程;它封装了中断策略,而不是您的任务代码;至少要有礼貌地设置中断标志!

有很多方法仍然可能导致中断,超时,JVM中断等。

如果我从来没有使用过interrupt()自己打断其他线程(例如,因为我正在使用其他方式取消我的工作线程,例如毒药和while(!cancelled)样式循环[如JCIP中所述),那该怎么办?那么InterruptedException是什么意思?抓到我该怎么办?关闭我的应用程序?

您需要在这里非常小心;如果您拥有引发InterruptedException(IE)的线程,那么您知道在捕获该线程后该怎么做,说您可以关闭您的应用程序/服务,或者可以用一个新的线程替换被杀死的线程!但是,如果您不拥有该线程,则在捕获IE时要么将其重新抛出到调用堆栈的上方,要么在执行某些操作(可能正在记录)之后,重置中断状态,以便拥有该线程的代码在控制权到达时可以了解线程被中断并因此采取措施,因为只有线程知道中断策略。

希望这会有所帮助。


0

InterruptedException说的例行可以被中断,但不一定,这将是。

如果您不希望中断,则应将其视为可能发生的任何其他意外异常。如果在关键部分中,意外的异常可能会带来令人讨厌的后果,则最好尝试清理资源并正常关闭(因为收到中断信号,表明您在使用精心设计的不依赖中断的应用程序在某种程度上,它不是经过设计的,因此肯定有问题。或者,如果所讨论的代码不重要或无关紧要,则可能要忽略(或记录)中断并继续执行。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.