Thread#stop()
已被弃用,因为它是“固有不安全的”,如果可能的话应该避免使用。
它是不稳定和容易出错的源头,而且可能会失败!
它实际上会导致目标线程抛出一个ThreadDeath
异常。无论如何,代码作者都不太可能预料到这种结果。对象可能处于不一致的状态,外部资源可能被占用并泄漏,文件可能只写了一部分。
有处理意外错误的方法,但实际上大多数代码都是假设它知道可能抛出哪些异常而编写的,并没有预料到这样的“惊喜”。
由于ThreadDeath
是一个Throwable
,任何catch(Throwable t)
都可以捕获它,除非在线程执行的每个代码片段中都非常小心(不现实),否则ThreadDeath
可能会被吸收而不结束线程。
正确的处理方式是声明一个原子变量(通常作为表示任务的Runnable
的一部分)。
AtomicBoolean stopThread=new AtomicBoolean(false);
然后将循环写成:
while (!stopThread.get()) {
System.out.println(1);
}
并提供一个方法:
public void stopThread(){
stopThread.set(true);
}
或者你可以使用 interrupt()
并检查 interrupted()
。这些是在 Thread
类中提供的更简洁的方法。当调用 interrupted()
时,它会清除标志位。但这并不总是有帮助的,虽然可以通过 Thread.currentThread().isInterrupted()
来检查标志位,但“检查标志位会清除标志位”的行为可能会导致一些未被预期的异常抛出,类似于 stop()
方法存在的一些问题。正确的方法是使用自己的标志位,并完全控制进程何时决定退出。
随你选择。
另请参阅:Java 线程原语废弃
你是否曾经想过为什么在某些并发进程上点击“取消”后,你经常需要等待很长时间才能得到响应?这就是原因。任务需要达到一个明确定义的点,并进行任何必要的清理以以明确定义的方式终止。
把Thread#stop()
方法看作是通过踢下车来停止骑自行车的人。该方法向他们挥舞红旗,然后他们会尽可能安全地停下来。
Thread#stop()
从未应该出现在Java中,你也永远不应该使用它。你可以在开发和小型系统中使用它,但在大型生产环境中会造成混乱。它不仅被弃用为“不推荐使用”,而且是“固有不安全”的,请勿使用它。它已经被弃用多年了,令人失望的是从未公布过任何“删除日期”。
以下是一个示例,根据您选择的危险程度,使用Thread#stop()
或interrupt()
方法。
import java.lang.System;
import java.lang.Thread;
class Ideone
{
private static boolean beDangerous=true;
public static void main (String[] args) throws java.lang.Exception
{
PrimeFactor factor=new PrimeFactor();
try{
for(int i=1;i<30;++i){
Thread thrd=new Thread(new Primer(factor));
thrd.start();
Thread.sleep(10);
if(beDangerous){
thrd.stop();
}else{
thrd.interrupt();
}
thrd.join();
if(!factor.check()){
System.out.println("Oops at "+i);
}
}
}catch(Throwable t){
System.out.println(t);
}
}
private static class Primer implements Runnable {
private PrimeFactor factor;
public Primer(PrimeFactor ifactor){
factor=ifactor;
}
public void run(){
int i=1;
while(!Thread.interrupted()){
factor.set(i++);
}
}
}
private static class PrimeFactor {
private long num;
private long prime;
public static long getFactor(long num){
if(num<=1){
return num;
}
long temp=num;
long factor=2;
for(int i=2;temp!=1;++i){
if(temp%i==0){
factor=i;
do{
temp=temp/i;
}while(temp%i==0);
}
}
return factor;
}
public synchronized void set(long value){
num=value;
prime=getFactor(value);
}
public synchronized boolean check(){
return prime==getFactor(num);
}
}
}
典型的部分输出:
Oops at 1
Oops at 2
Oops at 3
Oops at 6
Oops at 8
请注意,
PrimeFactor
类可以被描述为线程安全的。所有它的方法都是
synchronized
的。想象一下它在某个库中。期望“线程安全”意味着
Thread#stop()
安全是不现实的,唯一的方法是很突兀。将其调用放入
try-catch(ThreadDeath tde)
块中并不能解决任何问题。损坏将在捕获之前就已经发生了。
不要让自己相信将
set()
更改为以下内容即可解决问题:
public synchronized void set(long value){
long temp=getFactor(value);
num=value;
prime=temp;
}
首先,执行任务期间可能会抛出“ThreadDeath”异常,所以这只是增加了竞争条件发生的几率。它并没有被否定。永远不要关于竞争条件发生的可能性进行讨论。“程序调用方法的次数多达数十亿次,因此每次都有可能发生一次千载难逢的情况。”
如果使用“Thread#stop()”,你基本上不能使用任何库对象,包括“java.*”,并且需要费尽周折地处理代码中的每个位置可能出现的“ThreadDeath”异常,但几乎肯定最终还是会失败。
while (true)
条件的方法吗? - Amit BeraFuture#cancel(true)
会有任何问题吗? - rkosegiThread#stop()
是你唯一的选择,但是 a) 它是一个糟糕、易泄漏的机制,可能会破坏整个应用程序,b) 仍然可能无法杀死线程,因为它只是在线程中抛出异常。 - Marko Topolnik