问题 总是调用Thread.currentThread()。interrupt();捕获InterruptedException时?


这篇IBM developerWorks文章 状态:

“有一次,当你知道线程即将退出时,吞下一个中断是可以接受的。只有当调用可中断方法的类是a的一部分时,才会出现这种情况 Thread不是 Runnable [...]”。

我总是实施 Runnable 我的线程到现在为止。给...一个 Runnable 像这样的实现:

public class View() implements Runnable {
    @Overload
    public void run(){
        Thread worker = new Thread(new Worker());
        worker.start();
        do{
            try{
                TimeUnit.SECONDS.sleep(3);
                updateView();
            }catch(InterruptedException e){
                worker.interrupt();
                // Thread.currentThread().interrupt();
                return;
            }
        }while(true);
    }

    protected void updateView(){
        // …
    }
}

是否真的有必要打电话 Thread.currentThread().interrupt(); 就在我之前 return; 声明?不 return; 已经执行一个干净的enaugh出口?叫它有什么好处?文章指出应该这样做,因为否则“[...]代码更高的代码将无法找到它[...]”。一个帖子的好处是什么? Thread.State.TERMINATED 在应用程序关闭时没有它的中断标志设置?你能给我一个例子吗? Runnable 出于明智的原因检查中断的旗帜?

顺便说一句,这是一个更好的代码设计扩展 Thread 而不是实施 Runnable


1495
2017-11-20 10:49


起源

看到 扩展线程与实现Runnable 普遍的共识是实施 Runnable。 - OldCurmudgeon


答案:


它会重置中断标志。这个 Java专家通讯 更详细地介绍了这个令人困惑的主题。

在我的例子中,在我捕获InterruptedException之后,我使用了   Thread.currentThread()。interrupt()立即中断了   线程再次。为什么这有必要?当抛出异常时,   中断标志被清除,所以如果你有嵌套循环,你会   在外循环中造成麻烦

因此,如果您知道您的代码不会被其他组件使用,那么您不需要重新中断。但是我真的不会做那个小小的优化。谁知道你的代码将来如何被使用/重用(甚至通过复制/粘贴),因此我会为每个中断重置标志。


10
2017-11-20 10:52





这是一个返回它还不够的例子:

public void doSomething1() {
  while (someCondition1()) {
    synchronized {
       try {
         this.wait();
       } catch (InterruptedException e) {
         return; // Should be Thread.currentThread().interrupt();
       }
    }
  }
}
public void doSomething2() {
  while (someCondition2()) {
    doSomething1();
  }
}

当异常throw在下次执行doSomething1()时清除中断状态时,状态被清除,线程不会终止。


3
2017-11-20 11:24





我更喜欢延伸 Thread 因为它可以让你更好地理解线程正在做什么,但它不一定是更好的代码设计。

正如布莱恩所说,它重置了中断标志,但这并没有多说。在你的情况下,它什么也不做 View-Thread将继续运行。

在中断Thread时,标准过程是Thread应该停止运行。它不会自动执行此操作,您必须实现一种方法,以便在中断后停止它。

使用内置功能有两种选择:

  • 将主循环放在try-block中 InterruptedException。这样,当它被中断时,你将被抛出循环,方法将退出。
  • 如果你必须保存状态,上面可能是坏的,因为它可能会破坏状态。作为替代方案,您可以设置interrupt-flag(如抛出时所说的那样。重新中断它中断线程

无论哪种方式,您都必须检查线程是否在您的while循环中被中断(使用 !Thread.currentThread().isInterrupted() - while循环中的语句)或者它可能/不会退出。你没有完成第一个选项之一,也没有检查标志,所以你的 View-thread将在被打断后继续运行。


1
2017-11-20 11:01



扩展线程是 一个不好的做法... - assylias
@assylias没有什么说这是一个不好的做法。对于某些问题,实现Runnable可能是首选,但正如我所说,为了解它是如何工作的,Thread是一个很好的方法。 - ddmps


是否真的有必要打电话 Thread.currentThread().interrupt(); 就在我之前 return; 声明?

作为一个观点,我总是这样做。我们所有的复制粘贴代码和吞下中断都是一个严重的问题,我通常都是这样 总是 做到这一点,即使线程即将死亡。

return; 已经进行了足够干净的退出?

如果你确定它是之前的最后一次回归 run() 方法完成并且线程退出,然后是,它在技术上不必要。但见上文。对于后代, return; 对中断标志没有任何作用。

问题是你的 View 班已被包裹。你确定当你回来时你正在退出 Thread。也许有人委托给它。 AOP可能会用来做某种仪器。

叫它有什么好处?文章指出应该这样做,因为否则“[...]代码更高的代码将无法找到它[...]”。

通常,当代码被需要中断标志的某种包装代码(委托,AOP等)调用时,不要吞下中断是很重要的。如果你吞咽它,包装将无法使用它。但在这种情况下,没有任何好处。

Thread.State.TERMINATED中的一个线程有什么好处,在应用程序关闭时没有设置中断标志?

没有。一旦线程退出中断状态就毫无价值。实际上,看起来线程死后,中断状态甚至不会持久存在。

Thread thread = new Thread(new Runnable() {
    public void run() {
        try {
            Thread.sleep(100);
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
            System.out.println("caught");
        }
    }
});
thread.start();
thread.interrupt();
System.out.println(thread.isInterrupted());
thread.join();
System.out.println(thread.isInterrupted());

打印:

true
caught
false

你能举个例子说明Runnable以外的代码是否有合理的原因检查中断的标志?

我不能。线程之外没有代码 run() 方法,除非有人在您不知情的情况下将runnable包装在其他代码中。

如果您使用的话可能会发生这种情况 ExecutorService 但在这种情况下,线程的中断状态通过a特别清除 wt.isInterrupted() 在工作开始之前。

再说一次,原因是因为它是一个很好的模式,而这正是软件工程中的重要因素。


0
2018-05-09 22:01



我刚刚遇到它的一个具体例子是ExecutorService的shutDownNow逻辑。正在检查中断状态以取消正在运行的任务。如果Callable或Runnable没有设置中断状态,则任务将运行完成,如果您正试图以正常方式立即停止线程池,则可能不需要该任务。 所以任何无法响应中断的任务都可能永远不会终止。 - Draukadin