说我有以下代码:
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. */
}
}
}
停止循环,但对我没有帮助。由于每个函数都执行可能需要几分钟的事情并且有许多不同的函数,因此在每个函数之前检查中断标志是否为一个可能是昂贵的(特别是因为大多数时候应用程序运行顺利)。
我想知道是否有一种特殊机制可用于解决这类问题。
答案 0 :(得分:3)
API documentation对此很清楚:
如果在调用Object类的wait(),wait(long)或wait(long,int)方法,或者join(),join(long),join(long)时阻塞了这个线程,int),sleep(long)或sleep(long,int),这个类的方法,然后它的中断状态将被清除,它将收到InterruptedException。
如果此线程在InterruptibleChannel上的I / O操作中被阻塞,则通道将关闭,线程的中断状态将被设置,线程将收到ClosedByInterruptException。
如果在Selector中阻塞了这个线程,那么线程的中断状态将被设置并且它将立即从选择操作返回,可能具有非零值,就像调用选择器的唤醒方法一样。
如果以前的条件都不成立,那么将设置该线程的中断状态。
因此,如果您正在等待对象监视器,则只能依赖此异常。某些I / O操作引发了一些其他异常,但如果您也不使用它们,则除了检查interrupted()
标志之外别无选择。
你可以做的是重新组织你的代码:如果你有一个接一个地调用的N
方法,是不是可以把它们抽象成一个循环?通常情况下,可以找到重构代码以支持中断的方法,具体方法取决于您的实际情况。我的第一个问题是:为什么单个方法运行几分钟?这听起来有点可疑(尽管可能是合理的)。
无论哪种方式,可中断性都不是免费的,如果您希望代码对中断的响应比主循环的长度更快,则必须主动设计中断点。
还有一件事:检查interrupted()
标志肯定是 NOT 代价高昂。当你在主循环中花费几分钟时,它并不比构造和处理异常便宜得多。我甚至可以说,与Thread.isInterrupted()
的通话相比,你发现的事情要快得多。
答案 1 :(得分:3)
实际上,如果你在方法中进行CPU绑定工作,你必须自己检查Thread.interrupted()
并自己抛出InterruptedException
。除非你停在一些专门设计的空间,例如Semaphore.wait()
等,否则Java不会神奇地为你做这件事。
答案 2 :(得分:2)
你的第二个例子将在中断后继续循环。这是因为InterruptedException
实际上并不意味着设置了Thread的中断标志;事实上,你根本不需要检查它。
要解决此问题,您可以简单地重新中断线程(以允许调用者知道线程被中断),然后中断:
public void run(){
while (true) {
try {
function1();
//...
functionN();
} catch (InterruptedException ex) {
Thread.currentThread().interrupt();
break;
}
}
}
答案 3 :(得分:2)
正如书中所述" Java并发实践" :" Java没有提供任何机制来安全地强制线程停止正在做的事情,所以你必须在你身边实现一些东西。检查中断的标志并处理InterruptedException是管理线程取消的最佳方法。 如果你们其中一个function1()... functionN()处于数据库事务的中间,或者HTTP调用由你的程序来处理取消;您可以等到n秒并保存当前状态或取消事务和roolback,执行的操作由您的应用程序逻辑决定。