调用Thread.interrupt()在Thread.join()之前,是否会立即导致join()抛出InterruptedException?

16
基本上,问题标题所说的就是这样。
Thread t = new Thread(someRunnable);
t.start();
t.interrupt();
t.join(); //does an InterruptedException get thrown immediately here?

从我的测试来看,似乎是这样的,但我想确保一下。我猜测Thread.join()在执行其“等待”例程之前会检查线程的interrupted状态吗?


3
不,Thread.join() 只关心对当前线程的中断。 - user207421
3个回答

26
调用Thread.interrupt()在Thread.join()之前会导致join()立即抛出InterruptedException吗?
不会,只有当正在调用join()方法的当前线程被中断时,join()才会抛出InterruptedException。t.interrupt()是中断刚刚启动的线程,而t.join()只有在执行join操作的线程(可能是主线程?)本身被中断时才会抛出InterruptedException。
 Thread t = new Thread(someRunnable);
 t.start();
 t.interrupt();
 t.join();  // will _not_ throw unless this thread calling join gets interrupted

此外,重要的是要意识到中断线程并不会取消它,并且join()与Future不同,它不会返回线程抛出的异常。
当您中断一个线程时,线程正在调用sleep()、wait()、join()和其他可中断方法的所有调用都将抛出InterruptedException。如果没有调用这些方法,则线程将继续运行。如果一个线程响应中断并抛出InterruptedException然后退出,那么该异常将丢失,除非您使用了t.setDefaultUncaughtExceptionHandler(handler)。
在您的情况下,如果线程被中断并因为返回而完成,则join将完成——它不会抛出异常。处理中断的常见线程代码如下:
 public void run() {
    try {
       Thread.sleep(10000);
    } catch (InterruptedException e) {
       // a good pattern is to re-interrupt the thread when you catch
       Thread.currentThread().interrupt();
       // another good pattern is to make sure that if you _are_ interrupted,
       // that you stop the thread
       return;
    }
 }

点赞;但是说重新中断线程是“一种好的模式”可能会让人感到困惑。如果您已经打断了逻辑流,那么中断的原始意图现在是否已经实现了呢?我想再多谈一点...立即返回;或者清理需要清理的任何内容并立即返回。无论如何,“中断”都很棘手;它是一种危险的语言特性,由多个方面以多种方式使用...只有当您执行将识别该状态的下游代码时,重新中断才可能是必要的。 - Robert
这是一个很好的模式@Robert,因为您不知道调用者是否还需要检查线程的中断状态。在这些情况下可能只需要重新中断,但这总是一个好模式,因为我们倾向于复制代码以传播不良模式。我不是唯一一个这样认为的人。 - Gray
我的观点很简单:如果不知道调用方在做什么,有些情况下重新中断是正确的选择,而有些情况则不是。无论如何,这是对每个人的一个良好提醒:不能想当然地使用中断!在我看来,除非你确切知道它将如何影响所有上游/下游代码,否则应避免将其作为控制流机制。 - Robert
这是一个不错的模式,Robert。像所有的模式一样,也有例外。我鼓励你在这个主题上多读一些。我并没有提出任何激进的建议。 - Gray
我对这个主题很了解,我的理解没有问题(但感谢你的鼓励)。你的帖子有很多好东西 - 但是你帖子和评论中的讽刺之处在于你推广代码的复制/粘贴(同时又警告不要这样做),并说“这是一个好模式”,但你没有说明为什么。我只是建议你为这个陈述辩护(或者链接到关于“模式”的信息)。理解“为什么”很重要。特别是对于一个“模式”:什么时候遵循这个模式很重要。 - Robert
不确定我是否通过展示良好的模式来推广复制粘贴。至于“何时”,我会说“总是”,除非你有充分的理由不这样做。这个问题不是关于中断的,否则我会给出解释。以下是一些好的链接: https://dzone.com/articles/why-do-we-need-threadcurrentthreadinterrupt-in-int https://praveer09.github.io/technology/2015/12/06/understanding-thread-interruption-in-java/ https://www.baeldung.com/java-interrupted-exception 如果对我的这个主题经验有任何疑问,请查看https://stackoverflow.com/tags/multithreading/topusers - Gray

20
< p > interrupt()方法中断的是被中断的线程,而不是执行中断操作的线程。

c.f.

Thread.currentThread().interrupt();
t.join(); // will throw InterruptedException 

1

interrupt()会中断引用线程的执行,如果它受到sleep()wait()join()的影响。

  1. 由于主函数没有调用sleep / join / wait,因此这只会更新interrupted标志。
  2. 验证语句1。
  3. t1.join()暂停MAIN thread的执行,并允许t1在MAIN thread继续之前执行。但是,似乎主函数在内部检查Thread.currentThread().isIntercepted()并通过引发异常处理。
  4. 验证语句3。
  5. 验证语句3,同时,由于异常已被引发,intercepted标志被重新设置为false。

示例代码:

        t1.start();
        System.out.println(Thread.currentThread().getName()+" isInterrupted(): "+Thread.currentThread().isInterrupted());
        try {
            Thread.currentThread().interrupt(); // -- 1
            System.out.println(Thread.currentThread().getName()+" isInterrupted(): "+Thread.currentThread().isInterrupted()); // -- 2
            t1.join(); // -- 3
            System.out.println("This is never called as exception is raised"); // -- 4
        }catch(InterruptedException ex){
            System.out.println(Thread.currentThread().getName()+" isInterrupted(): "+Thread.currentThread().isInterrupted()); -- 5
        }
        System.out.println("Main continues");

输出:

main isInterrupted(): false
Thread-0: 0
main isInterrupted(): true
main isInterrupted(): false
Main continues
Thread-0: 1
Thread-0: 2
Thread-0: 3

上面的调用来自于 main() 我希望这可以更好地帮助理解。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接