【问题标题】:Java Threads: Shutdown flag vs Catching ExceptionJava 线程:关闭标志与捕获异常
【发布时间】:2011-07-27 15:39:37
【问题描述】:

在线程中处理取消时,你经常会看到这样的代码

while (!shutdown) {
  .. do something, if a blocking call, then it will throw the interrupted exception
  try { .. some more ... } 
  catch (InterruptedException e) { 
    shutdown = true; 
  }
}

我想知道的是,这是,或者为什么这样,比这样做更好

try {
  while (true) {
    .. do something, if a blocking call, then it will throw the interrupted exception
    if (Thread.interrupted()) throw new InterruptedException();
  }
} catch (InterruptedException e) {
  .. clean up, let thread end
}

我的看法是,在后一种情况下,您根本不需要关心 shutdown var。

【问题讨论】:

    标签: java multithreading request-cancelling


    【解决方案1】:

    我建议您使用 finally 来清理线程(因为它总是被调用),而不是仅仅为了打破循环而抛出异常。试试

    try {
      while (!Thread.interrupted()) {
        .. do something, if a blocking call, then it will throw the interrupted exception
      }
    } catch (InterruptedException e) {
      // handle exception
    } finally {
      .. clean up, let thread end
    }
    

    【讨论】:

      【解决方案2】:

      您不会使用异常作为退出条件的一种方式(至少通常不会,并且最好避免这种做法。)异常是针对 ... 提示鼓 ... 宣布异常、错误、通常或可能很糟糕的情况和条件。

      关机不是(通常)错误情况,因此至少从哲学/设计的角度来看,我更喜欢使用关机标志变量的第一个选项。

      此外,标志可以外部化为只读属性(例如,作为 getter)。然后线程外部的组件可以查看线程是否仍然处于活动状态(如果它们具有合法依赖的逻辑。)

      就个人而言,我不喜欢 Java 使用 InterruptedException,因为它通常不是一个异常,而是一个信号,通常是一个正常和预期的信号。哦,好吧。

      【讨论】:

        【解决方案3】:

        我认为第二种方式更干净。这是一篇关于同一点的好文章,它还指出了有关线程中断的一些 I/O 考虑因素。 http://www.javaspecialists.eu/archive/Issue056.html

        【讨论】:

          【解决方案4】:

          在第一个版本中,您可以与调用代码共享关闭标志(或类似的关闭机制),允许它通过设置标志尝试完全正常关闭,而不会中断线程 - 可能会退回到中断如果正常关闭失败。

          我不建议使用线程中断作为您的only关闭机制。

          (当然,同样,要小心处理共享标志的方式。您需要使其成为线程安全的;在简单的情况下,一个 volatile 变量可能就足够了。)

          【讨论】: