您不能在 Java 中强制停止线程。
是的,有像 Thread.stop() 和相关的方法,但它们已被弃用多年 for good reason。
为什么不推荐使用Thread.stop?
因为它本质上是不安全的。停止线程会导致它解锁所有已锁定的监视器。 (监视器在ThreadDeath 异常向上传播时解锁。)如果以前受这些监视器保护的任何对象处于不一致状态,其他线程现在可能会以不一致的状态查看这些对象。据说这些物体已损坏。当线程对损坏的对象进行操作时,可能会导致任意行为。这种行为可能很微妙且难以检测,也可能很明显。与其他未经检查的异常不同,ThreadDeath 以静默方式杀死线程;因此,用户没有警告他的程序可能已损坏。损坏可以在实际损坏发生后的任何时间出现,甚至在未来几小时或几天内。
由于上述原因,您不应使用这些方法,也不应依赖它们工作(许多具有大量线程方法的 API 会很乐意忽略对 stop() 和 interrupt() 的任何调用)。
一旦我们解决了这个问题,您仍然可以以一种优雅的方式为您的线程实现逻辑,以便在您要求它们时尽快终止。
你需要做两件事:
1.- 在 run() 方法中检查 Thread.interrupted()。像这样的:
@Override
public synchronized void run() {
while (yourFinishCondition && !Thread.interrupted()) {
// do stuff until you finish, or until the thread is interrupted from the outside
}
}
2.- 在您的 main 方法中的每个线程上调用 interrupt(),以便在需要时向它们发出终止信号,如下所示:
Thread.UncaughtExceptionHandler h = (thread, exception) -> {
thread0.interrupt();
thread1.interrupt();
thread2.interrupt();
};
一点 PoC:
public class Main {
static class MyThread extends Thread {
public MyThread(String s) {
super(s);
}
@Override
public synchronized void run() {
while(!Thread.interrupted()) {
if (new Random().nextInt(1000000) == 7) {
throw new RuntimeException(Thread.currentThread().getName()+" oops!");
}
}
System.out.println(Thread.currentThread().getName()+" interrupted");
}
}
public static void main(String[] args) {
final MyThread thread0 = new MyThread("thread0");
final MyThread thread1 = new MyThread("thread1");
final MyThread thread2 = new MyThread("thread2");
Thread.UncaughtExceptionHandler h = (thread, exception) -> {
System.out.println(exception.getMessage());
thread0.interrupt();
thread1.interrupt();
thread2.interrupt();
};
thread0.setUncaughtExceptionHandler(h);
thread1.setUncaughtExceptionHandler(h);
thread2.setUncaughtExceptionHandler(h);
thread0.start();
thread1.start();
thread2.start();
}
}
输出:
thread2 oops!
thread1 interrupted
thread0 interrupted
延伸阅读:https://www.securecoding.cert.org/confluence/display/java/THI05-J.+Do+not+use+Thread.stop()+to+terminate+threads