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

时间:2013-11-20 10:49:51

标签: java multithreading

This IBM developerWorks article州:

  

“当你知道线程即将退出时,吞下一个中断是可以接受的。仅当调用可中断方法的类是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以外的代码是否有明智的理由检查中断的旗帜?

BTW,扩展Thread而不是实施Runnable是一种更好的代码设计吗?

4 个答案:

答案 0 :(得分:10)

重置中断标志。这个JavaSpecialists newsletter更详细地介绍了这个令人困惑的话题。

  

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

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

答案 1 :(得分:3)

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

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()时清除中断状态时,状态被清除,线程不会终止。

答案 2 :(得分:1)

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

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

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

使用内置功能有两个选项:

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

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

答案 3 :(得分:0)

  

是否真的有必要在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,可能会发生这种情况,但在这种情况下,线程的中断状态会在作业运行之前用wt.isInterrupted()明确清除。

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