在while循环中,中断异常(InterruptedException)和isInterrupted的区别。

4
假设我有以下代码:

while(!Thread.currentThread().isInterrupted()){  
    //do something   
    Thread.sleep(5000);  
}

现在,Thread.sleep 抛出`InterruptedException`,因此应该像这样:
while(!Thread.currentThread().isInterrupted()){  
   //do something   
   try{  
     Thread.sleep(5000);    
   } catch(InterruptedException e){  

   }
}

如果我触发了catch,那么while循环会继续吗?还是需要调用Thread.currentThread().interrupt()?如果我调用这个方法,那么是否也会引起InterruptedException?否则我怎么会首先遇到异常呢?
此外,如果我有:
while (!Thread.currentThread().isInterrupted()){  
   //do something   
   callMethod();  
}  

private void callMethod(){  
   //do something  
   try {  
     Thread.sleep(5000);    
   } catch(InterruptedException e){  

   }
}

我的while循环会再次中断吗?


1
请参见:https://dev59.com/_2LVa4cB1Zd3GeqPsgks - David Lavender
这里是:https://dev59.com/-XNA5IYBdhLWcg3wSrqa - David Lavender
你应该阅读《被破坏的门铃法则》(http://www.javaspecialists.eu/archive/Issue146.html)。 - OldCurmudgeon
3个回答

2
在线程中调用interrupt方法本身并不会抛出异常,只有在标志位被设置后睡眠或等待时才会引发InterruptedException异常。可预测哪些情况将引发InterruptedException异常,因此被中断的线程具有控制权并可以选择如何响应。它是一个已检查的异常,因此很明显是什么引发了它。这不像ThreadDeath异常,可以在任何地方引发。
当抛出InterruptedException时,线程的中断状态会被重置。如果要恢复线程的中断状态,因为要稍后检查该标志并使其为真,请调用Thread.currentThread().interrupt()来设置它。
在中断期间不会发生任何与处理指令方式有关的异常情况。因此,如果您选择在循环中捕获InterruptedException并检查该标志以退出,则需要重置该标志:
while(!Thread.currentThread().isInterrupted()){  
   //do something   
   try{  
     Thread.sleep(5000);    
   } catch(InterruptedException e){  
        Thread.currentThread().interrupt();
   }
}

另外,您可以使用InterruptedException来退出循环:

try {
    while (!Thread.currentThread().isInterrupted()) {
        // do something
        Thread.sleep(5000);
    }
} catch (InterruptedException e) {
    // flag value is not used here, but still good style
    Thread.currentThread().interrupt(); 
}

如果这个代码片段是被中断的线程的全部运行方法,那么您可以不必再次设置中断状态,但如果您有组件被其他部分使用,您不希望一个行为不良的部分扼杀中断标志,以致于线程中的其他代码没有意识到中断。

2

实际上,你的问题更多关于try-catch-finally而不是多线程。

1) 如果sleep抛出一个Exceptioncatch块将执行,然后while循环继续。

2) 你做的事情和1)完全相同。

要退出while循环,请执行以下操作:

try{  
   while(!Thread.currentThread.isInterrupted){  
       //do something   
       Thread.sleep(5000);    
   }  
}
catch(InterruptedException e){  

}

在这种情况下,如果抛出了一个 Exception,那么 while 循环将被离开并执行 catch 块。

+1:不过我更喜欢在循环内部捕获异常,然后显式地中断或继续。 - BigMike
@BigMike 是的,这种方法完全符合Java的格言“更多的代码意味着更好的代码”。 - Marko Topolnik
2
@BigMike 换句话说,您更喜欢没有异常机制的语言。无论您喜不喜欢,异常都会控制流程;您只需以涉及更多代码的方式使它们控制流程即可。 - Marko Topolnik
@MarkoTopolnik 也许你是对的,我猜通常这取决于个人口味和场景。顺便说一下,我真的很讨厌Java,仍然热爱老旧的C ;) - BigMike
@Vakimshaar: 为什么?如果我在callMethod()内部使用try-catch,并且在catch中执行Thread.currentThread.interrupt(),那么循环不会中断吗? - Jim
显示剩余4条评论

1

Thread.sleep() 在抛出 InterruptedException 前会清除 "中断状态"。您需要在 catch 块中调用 Thread.currentThread().interrupt(),否则 while 条件很可能不会成功,因为当 callMethod 返回时,线程将始终处于 "未中断" 状态。

异常不是由 interrupt() 方法引起的,而是由在已被标记为 "中断" 的线程上阻塞的 sleep() 引起的。这在 此处 有更详细的解释。另请参见 此答案


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