[英]Interrupting a thread 'gracefully' while inside the main loop
说我有以下代码:
public void run(){
while (true){
function1();
...
functionN();
}
}
我想“优雅地”退出-对我来说,这意味着一旦我发送了关闭信号,并且当前线程在functionK()上,该线程将“中断”循环并退出运行。
所以我试过像这样使用Thread.interrupt():
public void run(){
while (true){
try {
function1();
...
functionN();
} catch (InterruptedException ex) {
/* Cleanup and exit. */
}
}
}
但这是行不通的-即使中断标志打开,线程也将继续无限运行。
仅作记录:
public void run(){
while (!thread.isInterrupted()){
try {
function1();
...
functionN();
} catch (InterruptedException ex) {
/* Cleanup and exit. */
}
}
}
停止循环,但是对我没有帮助。 由于每个功能执行可能需要几分钟的时间,并且有很多不同的功能,因此在每个功能之前检查中断标志是否为一个可能会花费很多(特别是因为大多数情况下,应用程序运行平稳)。
我想知道是否可以使用一种特殊的机制来解决此类问题。
API文档对此非常清楚:
如果在调用Object类的wait(),wait(long)或wait(long,int)方法或join(),join(long),join(long,int)方法时阻塞了此线程,sleep(long)或sleep(long,int)此类的方法,则其中断状态将被清除,并将收到InterruptedException。
如果此线程在InterruptibleChannel上的I / O操作中被阻止,则该通道将被关闭,该线程的中断状态将被设置,并且该线程将收到ClosedByInterruptException。
如果此线程在选择器中被阻塞,则该线程的中断状态将被设置,并且它将立即从选择操作中返回,可能具有非零值,就像调用选择器的唤醒方法一样。
如果上述条件均不成立,则将设置该线程的中断状态。
因此,仅在等待对象监视器时才可以依赖此异常。 某些I / O操作还会引发其他一些异常,但是如果您也不使用它们,则除了检查interrupted()
标志之外别无选择。
但是,您可以做的是重新组织代码:如果您有N
方法被一个接一个地调用,那么是否不可能将它们抽象为一个循环? 通常,可能会找到一种方法来重构代码以支持中断,确切的方法取决于您的实际情况。 我的第一个问题是:为什么一个方法要运行几分钟? 听起来有点可疑(尽管可能有道理)。
无论哪种方式,可中断性都不是免费提供的,如果您希望代码对中断的响应比主循环的长度更具响应性,则必须积极设计中断点。
不过,还有一件事:检查interrupted()
标志绝对不是昂贵的事情。 不是在主循环中花几分钟的时间,这比构造和处理异常要便宜得多。 我要说的是,您发现比调用Thread.isInterrupted()
更快的东西。
实际上,如果您在方法中执行CPU绑定工作,则必须自己检查Thread.interrupted()
并自己抛出InterruptedException
。 Java不会为您神奇地做到这一点,除非您将其停放在某些专门设计的空间中,例如Semaphore.wait()
等。
您的第二个示例将在中断后继续循环。 这是因为InterruptedException
实际上并不意味着设置了Thread的interrupted标志。 实际上,您根本不需要检查它。
要解决此问题,您可以简单地重新中断线程(以允许调用者知道该线程已被中断),然后中断:
public void run(){
while (true) {
try {
function1();
//...
functionN();
} catch (InterruptedException ex) {
Thread.currentThread().interrupt();
break;
}
}
}
如《 Java并发实践》一书中所述:“ Java没有提供任何安全地强制线程停止正在执行的操作的机制”,因此您必须自己执行一些操作。 检查中断标志并处理InterruptedException是管理线程取消的最佳方法。 如果您的其中一个function1()... functionN()在数据库事务中,或者HTTP调用取决于您的程序来处理取消; 您可以等到n秒并保存当前状态或取消事务并回滚,要执行的操作由您的应用程序逻辑决定。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.