如何终止一个Java线程?

4

我在谷歌上搜索了关于杀死Java线程的解决方案。目前存在两种解决方案:

  1. 设置一个标志位
  2. 使用Thread.interrupt

但是这两种方法都不适合我。因为我的线程调用了一个需要很长时间才能完成的第三方API,如果执行时间太长,我想让用户取消该线程。

那么我应该如何结束该线程呢?感谢您的帮助。


4
不必杀死它们,只需让它们自杀即可。 - Landei
8个回答

5

Thread.interrupt() 是通常适用的唯一安全方法。当然,您也可以使用其他应用程序级信号(例如对易失变量的条件检查)来自我终止。其他方法(如所有已弃用的 Thread.xx 方法)可能以不确定的方式污染应用程序状态,并且需要重新加载所有应用程序状态。


4
Thread.interrupt只是其中一部分,你要中断的线程必须支持使用中断标志的中断策略... 就是那个标志会在调用Thread.interrupt时被重置。 - Toby
大多数情况下,Thread.interrupt不能杀死线程,而是线程继续执行。在这种情况下,最好的解决方案是什么? - Kathir
是的,Ramin,请详细说明一下? - Nitesh Verma
@NiteshVerma 简单地从底层的Runnable的run()方法中返回将销毁线程。除非您的同步需要,否则没有必要join()线程。 - Yann Ramin
谢谢,我做得很好。此外,我发现这件事情相当概念化,如果你的线程基本概念没问题,那么很容易完成。 - Nitesh Verma
显示剩余3条评论

3

理论上,您可以调用被弃用的Thread.stop()方法。但是请注意,这可能会导致您的应用程序行为出现意外和不可预测的情况...这取决于第三方库实际正在执行什么操作。Thread.stop()和相关方法基本上是不安全的。

最好的解决方案是修改第三方库以响应Thread.interrupt。如果您无法这样做,则应该放弃它并找到/使用更好的库。


Future + Callable - Basil
这种方法不允许你强制停止一个线程。Future.cancel 方法使用 Thread.interrupt(),而我们已经被告知 Thread.interrupt() 不是一个解决方案。 - Stephen C

2
我会将调用需要长时间的第三方API放入一个Callable<DataTypeReturnedBy3rdPartAPI>中,然后使用SingleThreadExecutor执行它,并指定一个超时时间。按照这种方法,如果调用第三方API的时间超过timeOut,线程将被终止。以下是一些代码示例:
ExecutorService executor = Executors.newSingleThreadExecutor();
 try {
   //================= HERE ==================
   Future<Boolean> job = executor.submit(thirdPartyCallable);
   executor.awaitTermination(timeOut, TimeUnit.SECONDS);      
   if(!job.isDone())
     logger.debug("Long call to 3rd party API didn't finish");
   //=========================================
 } catch (Exception exc) {
     exc.printStackTrace();      
 } finally {
     if(!executor.isShutdown() )
       executor.shutdownNow();
 }

}  

private static Callable<Boolean>  thirdParytCallable = new Callable<Boolean>() {
  public Boolean call() throws Exception {
    //Call to long 3rd party API
    //.......
    for(long i = 0;i<99999991999999L;i++) {
      Thread.sleep(10L);// Emulates long call to 3rd party API
      System.out.print(".");
    }
    return Boolean.valueOf(true);//Data from 3rd party API
  }
}; 

Joshua Bloch的《Effective Java第二版》条款68:优先选择执行器和任务而不是线程。 - user454322

1
生成一个独立的进程并使用操作系统工具终止它。您需要调用“C”来完成此操作,但代码不会很多。您没有说明正在运行哪个操作系统。

好的,这应该可以工作,但是对我来说太重了,并且可能会增加集成和共享数据的复杂度。 - zjffdu

0

由于Thread.stop()已被(正确地)弃用,通常可以通过将标志设置为true来实现。类似这样:

调用类:

...
workListExecutor.stop()
...

WorkListExecutor.class:

boolean running = true;

void stop(){
  running = false;
}

void run(){
  while (running) {
    ... do my stuff ...
  }
}

假设您的线程有某种主循环(通常情况下是这样)。 如果循环中的代码太大,您可以定期检查running是否仍然为true,如果不是,则退出。

这样做的好处是在完成时仍然可以清理。当您的运行方法完成时,线程将自动终止。


0

你可以尝试使用 Thread.stop(),但是要自行承担风险(at your own risk)。最理想的情况是,你调用的API应该有一种中断操作的方式(如果API本身没有提供更干净的中断进度的方法,你尝试过 Thread.interrupt() 吗?)。


0

0
java.util.concurrent.FutureTask 中,超时取消机制会抛出 java.util.concurrent.TimeoutException 异常。
你可以将其视为自动中断某些超时操作。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接