有 Java 编程相关的问题?

你可以在下面搜索框中键入要查询的问题!

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

假设我有以下代码:

public void run(){
   while (true){
        function1();
        ...
        functionN();
   }
}

我想“优雅地”退出——这意味着一旦我发送了一个关闭信号,当前线程位于functionK(),线程就会“中断”循环并退出运行

所以我试着使用线程。中断()如下:

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. */
        }
   }
}

停止循环,但对我没有帮助。由于每个函数所做的事情可能需要几分钟,而且有很多不同的函数,因此在每个函数之前检查中断标志是否为1可能代价高昂(特别是因为应用程序在大多数情况下运行平稳)

我想知道是否有一种特殊的机制可以用来解决这种问题


共 (4) 个答案

  1. # 1 楼答案

    您的第二个示例将在中断后继续循环。这是因为InterruptedException实际上并不意味着设置了线程的中断标志;事实上,你根本不需要检查它

    要解决这个问题,只需重新中断线程(让调用方知道线程被中断),然后中断:

    public void run(){                                                                                  
      while (true) {                                                                                    
        try {                                                                                           
          function1();                                                                                  
          //...                                                                                  
          functionN();                                                                                  
        } catch (InterruptedException ex) {                                                             
          Thread.currentThread().interrupt();                                                           
          break;                                                                                        
        }                                                                                               
      }                                                                                                 
    }  
    
  2. # 2 楼答案

    关于这一点API documentation非常清楚:

    If this thread is blocked in an invocation of the wait(), wait(long), or wait(long, int) methods of the Object class, or of the join(), join(long), join(long, int), sleep(long), or sleep(long, int), methods of this class, then its interrupt status will be cleared and it will receive an InterruptedException.

    If this thread is blocked in an I/O operation upon an InterruptibleChannel then the channel will be closed, the thread's interrupt status will be set, and the thread will receive a ClosedByInterruptException.

    If this thread is blocked in a Selector then the thread's interrupt status will be set and it will return immediately from the selection operation, possibly with a non-zero value, just as if the selector's wakeup method were invoked.

    If none of the previous conditions hold then this thread's interrupt status will be set.

    因此,只有在等待对象监视器时,才能依赖此异常。某些I/O操作引发了几个其他异常,但是如果您也不使用它们,那么除了检查interrupted()标志外,没有其他选项

    不过,您可以做的是重新组织代码:如果有N方法被一个接一个地调用,那么不可能将它们抽象成一个循环吗?通常情况下,可以找到一种重构代码以支持中断的方法,具体方法取决于您的实际场景。我的第一个问题是:为什么一个方法要运行几分钟?这听起来有点可疑(尽管这可能是合理的)

    不管怎样,可中断性都不是免费的,如果希望代码对中断的响应比主循环的长度更灵敏,就必须积极地设计中断点

    不过,还有一件事:检查interrupted()标志绝对是昂贵的。当您在主循环中花费数分钟时就不会了,而且这比构造和处理异常要便宜得多。我甚至可以说,你会发现几乎没有什么事情比打电话给Thread.isInterrupted()更快

  3. # 3 楼答案

    实际上,如果您在方法中执行CPU限制的工作,您必须自己检查Thread.interrupted(),然后自己抛出InterruptedException。Java不会神奇地为你做到这一点,除非你把车停在一些特别设计的空间,比如Semaphore.wait()

  4. # 4 楼答案

    正如《实践中的Java并发》一书中所述:“Java没有提供任何机制来安全地强制线程停止正在做的事情”,因此您必须在自己这方面实现一些东西。检查中断标志并处理InterruptedException是管理线程取消的最佳方法。 如果你们中的一个函数1()。。。函数No()位于数据库事务的中间,或者HTTP调用由您的程序来处理取消;您可以等待到n秒并保存当前状态,或者取消事务并返回,要执行的操作由应用程序逻辑决定