繁体   English   中英

在主循环内“优雅地”中断线程

[英]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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM