【问题标题】:Interrupt / Kill a running thread中断/杀死正在运行的线程
【发布时间】:2011-12-23 11:17:52
【问题描述】:

在发生特定超时时,我需要杀死/取消/中断/使正在运行的线程失败。我使用 ExecutorService 来管理一个线程池,通过它我可以使用 Future 的 cancel() 方法取消任务,该方法将其从 ExecutorService 的视图中删除,但线程本身会继续运行。

在网上环顾四周,人们talk about interrupting threads 使用 isInterrupted() 方法有一个循环或正在等待可以通过表面 InterruptedException 处理的 IO。

杀死既不循环(或没有任何其他钩子)也不等待 IO 的线程的一般做法是什么?环顾四周,Thread.stop() 似乎做了我需要的(只是盲目地杀死线程)但不建议使用。

【问题讨论】:

  • “盲目地杀死线程”是你永远不应该做的事情。
  • Thread.stop() 只适用于可以理解在每一行都停止的结果的琐碎代码。这种类型的代码也很容易添加行来检查中断标志。也就是说,即使在理论上它也不是一个理想的解决方案。

标签: java multithreading


【解决方案1】:

如果你使用ExecutorService,那么你不应该弄乱它的线程:这个概念隐藏在执行器后面,它是比线程更高级别的概念,因此不提供管理它们的方法。我强烈建议您停止整个 Executor,而不是尝试停止其中一个线程。

请注意ExecutorService 中的线程正在循环,它们的循环包括等待任务队列中可用的任务。

在Java中没有简单的方法来停止一个不循环的线程,你可以做的是:

  • 有一个可变布尔标志,线程的Runnable 会不时检查它是否应该停止(可以用作线程循环中的条件的相同标志)。
  • 致电Thread.interrupt() 尝试(尽力而为,如果您不知道自己在做什么,则非常不安全)停止与同步相关的等待/锁定/获取/...线程被卡住了。

【讨论】:

    【解决方案2】:

    如果您已经收到了Executorservice,那么您已经收到了Future。因此,取消作业的唯一理智和干净的方法是调用future.cancel(boolean mayInterruptIfRunning)。设置mayInterruptIfRunning 将中断当前正在运行的作业,如果作业未运行则不执行任何操作。所以你只需要通过不时检查Thread.interrupted()来以一种尊重中断的方式编写作业。

    请注意 jobthread 之间的区别。你提交了一个job,因此你不应该通过试图绕过ExecutorService 来搞砸一个thread,这可能一点也不好玩。致电Future.cancel(true),您可以清楚地告知所有相关方该做什么。

    【讨论】:

    • 同意。但我想要一个相当于 SIGTERM/SIGKILL 组合的线程。我对无限运行或有缺陷的作业对我的系统来说可能很昂贵感到不满。
    【解决方案3】:

    我个人建议您选择中断路线,因为它是结束该线程的最干净和优雅的方式。

    让我们试着很好地定义我们的目标。线程只不过是一个单独的进程,它将执行您分配给它的一组任务。可能您必须在代码中找到可中断的点,并且必须在这些点上进行 interrupted() 检查。显然,这些观点应该已经达到了合乎逻辑的结局。

    例如,

    public void run(){
          if (Thread.currentThread().interrupted()) {
               return;
          }
          //LogicA start
          //LogicA end
          if (Thread.currentThread().interrupted()) {
               return;
          }
          //LogicB start
          //LogicB end
          if (Thread.currentThread().interrupted()) {
               return;
          }
          //LogicLong start
          //Long code here cannot end or exit or kill the thread now. Let it finish
          //LogicLong ends
          if (Thread.currentThread().interrupted()) {
               return;
          }
          //LogicD start
          //LogicD end
    }
    

    【讨论】:

    • 谨慎使用 Thread.interrupted():它重置了线程的中断状态,Java API 中的许多类都使用它,导致线程级别的中断被忽视。
    • 不完全。在这里给出更多上下文,线程通过接口实例化一个类并调用该类的特定方法。这些方法的实现是由我的系统的用户定义的,我确实预计会出现无限循环等缺陷。我想通过终止超过超时的作业来避免这种情况。
    • @NiranjanJayakar :在这种情况下,可能应该在无限循环开始时检查中断检查。
    猜你喜欢
    • 2022-11-08
    • 2018-12-10
    • 2012-05-31
    • 1970-01-01
    • 1970-01-01
    • 2013-10-26
    • 1970-01-01
    • 2019-02-18
    相关资源
    最近更新 更多