8

我不明白为什么线程InterruptedException在被中断时不会抛出异常。

我正在尝试以下代码段:

公共类中断测试{

public static void main(String[] args) {
    MyThread t = new MyThread();
    t.start();
    try {
        t.join();
    } catch (InterruptedException ex) {
        ex.printStackTrace();
    }
}

private static class MyThread extends Thread {

    @Override
    public void run() {
        Thread.currentThread().interrupt();
    }
} }

在 API 文档中,它在interrupt()方法上说:

如果该线程在调用 Object 类或 Thread.join()、Thread.join(long)、Thread 的 wait()、wait(long) 或 wait(long, int) 方法时被阻塞。 join(long, int), Thread.sleep(long), 或 Thread.sleep(long, int),这个类的方法,那么它的中断状态会被清除,它会收到一个InterruptedException。

4

4 回答 4

24

我知道这是一个老问题,但我认为上面的答案实际上并不完全正确。(除了@Skylion's,它并没有真正解决这个问题......):)

Thread.interrupt()本身不会抛出任何异常。它做了两件事:首先它简单地设置一个内部中断标志,然后它检查它被调用的线程当前是否阻塞了一个活动,如wait()sleep()join()。如果它找到一个,那么它会唤醒该方法并导致该方法在调用它的线程内(而不是从)抛出异常

在您interrupt()从线程本身调用的情况下,该线程显然当前不能阻塞其中一个调用,因为它当前正在执行您的interrupt()调用。因此,只设置了内部中断标志,根本不抛出异常。

下次您sleep()从该线程调用其中一个阻塞方法(如在@OldCurmudgeon 的示例中)时,方法将注意到中断- 标志并抛出InterruptedException.

如果您从未调用任何这些方法,您的线程将继续运行,直到它以其他方式终止并且永远不会抛出InterruptedException. 即使您interrupt()从不同的线程调用也是如此。

因此,要注意您的线程已被中断,您要么需要经常使用其中一种阻塞方法,InterruptedException当您收到其中一个异常时抛出一个然后退出,或者您需要经常调用Thread.interrupted()以检查内部中断- 标志自己如果它返回则退出true。但是您也可以完全忽略异常和结果Thread.interrupted()并保持线程运行。所以,interrupt()名字可能有点含糊。它根本不一定“中断”(如“终止”)线程,它只是向线程发送一个信号,线程可以随意处理或忽略。很像 CPU 上的硬件中断信号(这可能是名称的来源)。

要让主线程中的方法抛出异常join(),您需要调用线程,而不是 on interrupt(),如下所示:MyThread

public static void main(String[] args) {
    MyThread t = new MyThread();
    t.setDaemon(true);  // Quit when main thread is done
    t.start();
    try {
        t.join();
    } catch (InterruptedException ex) {
        System.out.println("Now it works:");
        ex.printStackTrace();
    }
}

private static class MyThread extends Thread {
    
    private final Thread parentThread;
    
    public MyThread() {
        parentThread = Thread.currentThread();
    }

    @Override
    public void run() {
        parentThread.interrupt();  // Call on main thread!!!
        while (true);  // Keep thread running (see comments)
    }
}
于 2018-03-02T20:43:27.437 回答
0

为什么要中断线程?只需使用

return;
于 2013-10-03T23:45:30.813 回答
0

请参阅@markus-a 的答案,了解此处应接受的答案。(我的应该被删除,但在它被接受时我不能这样做)。


异常总是在它们自己的线程上抛出。你有两个不同的线程:你的主线程和你创建的线程。MyThread 中抛出的异常无法在主异常中捕获。

于 2013-10-03T23:28:28.330 回答
-1

你太快了 - 试试这个:

private static class MyThread extends Thread {

  @Override
  public void run() {
    try {
      Thread.currentThread().interrupt();
      Thread.sleep(5000);
    } catch (InterruptedException ex) {
      Logger.getLogger(Test.class.getName()).log(Level.SEVERE, "Oops", ex);
    }
  }
}

我得到:

Oct 04, 2013 12:43:46 AM test.Test$MyThread run
SEVERE: Oops
java.lang.InterruptedException: sleep interrupted
at java.lang.Thread.sleep(Native Method)
at test.Test$MyThread.run(Test.java:36)

请注意,您不能将异常传播到run方法之外,因为run不会引发任何异常。

于 2013-10-03T23:46:31.663 回答