如何在Java中杀死一个线程?

如何在Java中杀死java.lang.Thread ?

590026 次浏览

请看这个Sun关于他们为什么弃用Thread.stop()的帖子。它将详细说明为什么这是一个糟糕的方法,以及应该做些什么来安全地停止线程。

他们推荐的方法是使用一个共享变量作为标志,要求后台线程停止。这个变量可以由请求线程终止的另一个对象设置。

一般来说你不会…

你可以使用Thread.interrupt() (javadoc link)命令它中断正在做的事情

在javadoc 这里(java technote链接)中有一个很好的解释

一种方法是设置一个类变量并将其用作哨兵。

Class Outer {
public static volatile flag = true;


Outer() {
new Test().start();
}
class Test extends Thread {


public void run() {
while (Outer.flag) {
//do stuff here
}
}
}


}

设置一个外部类变量,如上面例子中的flag = true。将其设置为false以“杀死”线程。

当然,也有运行某种不完全受信任的代码的情况。(就我个人而言,我允许上传的脚本在我的Java环境中执行。是的,到处都有安全警报,但这是应用程序的一部分。)在这种不幸的情况下,您首先只是希望脚本作者尊重某种布尔运行/不运行信号。如果线程运行的时间超过了某个超时,那么惟一合适的故障安全措施就是在线程上调用stop方法。

但是,这只是“体面的”,而不是绝对的,因为代码可以捕获ThreadDeath错误(或您显式抛出的任何异常),而不是像一个绅士线程应该做的那样重新抛出它。所以,AFAIA的底线是没有绝对的故障保险。

在Java中,线程不会被杀死,但是线程的停止是在合作方式中完成的。线程被要求终止,然后线程可以优雅地关闭。

通常使用volatile boolean字段,线程定期检查并在设置为相应值时终止该字段。

不会使用boolean来检查线程是否应该终止。如果你使用volatile作为字段修饰符,这将可靠地工作,但如果你的代码变得更复杂,因为在while循环中使用其他阻塞方法,可能会发生,你的代码将完全没有终止或至少需要更长的时间,如你所愿。

某些块库方法支持中断。

每个线程都已经有一个布尔标志中断状态,你应该利用它。它可以这样实现:

public void run() {
try {
while (!interrupted()) {
// ...
}
} catch (InterruptedException consumed)
/* Allow thread to exit */
}
}


public void cancel() { interrupt(); }

源代码改编自Java并发性实践。因为cancel()方法是公共的,你可以让另一个线程调用这个方法。

这个问题相当模糊。如果你的意思是“我如何编写一个程序,使线程在我希望它停止运行时停止运行”,那么各种其他回答应该是有帮助的。但如果你的意思是“我有一个紧急服务器,我现在不能重新启动,我只是需要一个特定的线程死亡,不管发生什么”,那么你需要一个干预工具来匹配jstack这样的监控工具。

为此,我创建了jkillthread。请参阅其使用说明。

你有办法做这件事。但如果你不得不使用它,要么你是一个糟糕的程序员,要么你使用的是一个糟糕的程序员编写的代码。所以,你应该考虑停止成为一个糟糕的程序员或停止使用这些糟糕的代码。

.这个解决方案只适用于没有其他方法的情况
Thread f = <A thread to be stopped>
Method m = Thread.class.getDeclaredMethod( "stop0" , new Class[]{Object.class} );
m.setAccessible( true );
m.invoke( f , new ThreadDeath() );

没有办法优雅地终止线程。

您可以尝试中断线程,一个常用的策略是使用毒丸来通知线程停止自己

public class CancelSupport {
public static class CommandExecutor implements Runnable {
private BlockingQueue<String> queue;
public static final String POISON_PILL  = “stopnow”;
public CommandExecutor(BlockingQueue<String> queue) {
this.queue=queue;
}
@Override
public void run() {
boolean stop=false;
while(!stop) {
try {
String command=queue.take();
if(POISON_PILL.equals(command)) {
stop=true;
} else {
// do command
System.out.println(command);
}
} catch (InterruptedException e) {
stop=true;
}
}
System.out.println(“Stopping execution”);
}


}

BlockingQueue<String> queue=new LinkedBlockingQueue<String>();
Thread t=new Thread(new CommandExecutor(queue));
queue.put(“hello”);
queue.put(“world”);
t.start();
Thread.sleep(1000);
queue.put(“stopnow”);

< a href = " http://anandsekar.github。io / cancel-support-for-threads " rel = " http://anandsekar.github.io/cancel-support-for-threads/ nofollow”> < / >

试图突然终止线程是众所周知的糟糕编程实践,也是糟糕应用程序设计的证据。多线程应用程序中的所有线程显式或隐式地共享相同的进程状态,并被迫相互协作以保持一致,否则您的应用程序将容易出现很难诊断的错误。因此,开发人员有责任通过仔细和清晰的应用程序设计来保证这种一致性。

对于受控线程终止,有两种主要的正确解决方案:

  • 使用共享volatile标志
  • 使用Thread.interrupt()和Thread.interrupted()方法。

关于突发线程终止相关问题的详细解释,以及受控线程终止的错误和正确解决方案的示例,可以在这里找到:

https://www.securecoding.cert.org/confluence/display/java/THI05-J.+Do+not+use+Thread.stop%28%29+to+terminate+threads

我想根据所积累的意见补充几点看法。

  1. 如果安全管理器允许,Thread.stop()将停止线程。
  2. Thread.stop()是危险的。话虽如此,如果你在一个JEE环境中工作,你无法控制被调用的代码,它可能是必要的;看到为什么是线程。弃用停吗?
  3. 永远不要停止容器工作线程。如果您想要运行容易挂起的代码,(小心地)启动一个新的守护进程线程并监视它,必要时杀死它。
  4. stop()调用线程上创建一个新的ThreadDeathError错误,然后将该错误抛出到目标线程上。因此,堆栈跟踪通常毫无价值。
  5. 在JRE 6中,stop()检查安全管理器,然后调用调用stop0()stop1()stop0()是本机代码。
  6. 截至Java 13, Thread.stop()尚未被删除(尚未),但Thread.stop(Throwable)已在Java 11中删除。(邮件列表 jdk - 8204243)

我会投票给Thread.stop()

例如,你有一个长时间的操作(像网络请求)。 假设您正在等待响应,但这可能需要时间,并且用户导航到其他UI。 这个等待线程现在是a)无用的b)潜在的问题,因为当他得到结果时,它是完全无用的,他将触发回调,从而导致大量错误

所有这些,他可以做响应处理,这可能是CPU密集。而你,作为一个开发人员,甚至不能停止它,因为你不能在所有代码中抛出if (Thread.currentThread().isInterrupted())行。

因此,无法强制停止线程是很奇怪的。

这里有一些关于这个主题的好读物:

如何处理InterruptedException?< / >

干净地关闭线程

我没有得到中断工作在Android,所以我用这个方法,工作完美:

boolean shouldCheckUpdates = true;


private void startupCheckForUpdatesEveryFewSeconds() {
Thread t = new Thread(new CheckUpdates());
t.start();
}


private class CheckUpdates implements Runnable{
public void run() {
while (shouldCheckUpdates){
//Thread sleep 3 seconds
System.out.println("Do your thing here");
}
}
}


public void stop(){
shouldCheckUpdates = false;
}

通常不杀死、停止或中断线程(或检查它是否被中断()),而是让它自然终止。

这很简单。你可以在run()方法中使用任何循环和(volatile)布尔变量来控制线程的活动。您还可以从活动线程返回到主线程以停止它。

这样你就优雅地杀死了一个线程:)。

“杀死一个线程”不是一个正确的短语。这里有一种方法我们可以在will上实现线程的优雅完成/退出:

我使用的Runnable:

class TaskThread implements Runnable {


boolean shouldStop;


public TaskThread(boolean shouldStop) {
this.shouldStop = shouldStop;
}


@Override
public void run() {


System.out.println("Thread has started");


while (!shouldStop) {
// do something
}


System.out.println("Thread has ended");


}


public void stop() {
shouldStop = true;
}


}

触发类:

public class ThreadStop {


public static void main(String[] args) {


System.out.println("Start");


// Start the thread
TaskThread task = new TaskThread(false);
Thread t = new Thread(task);
t.start();


// Stop the thread
task.stop();


System.out.println("End");


}


}

线程。停止是不赞成的,所以我们如何停止一个线程在Java ?

总是使用中断方法和未来请求取消

  1. 当任务响应中断信号时,例如阻塞队列采取方法。
Callable < String > callable = new Callable < String > () {
@Override
public String call() throws Exception {
String result = "";
try {
//assume below take method is blocked as no work is produced.
result = queue.take();
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
return result;
}
};
Future future = executor.submit(callable);
try {
String result = future.get(5, TimeUnit.SECONDS);
} catch (TimeoutException e) {
logger.error("Thread timedout!");
return "";
} finally {
//this will call interrupt on queue which will abort the operation.
//if it completes before time out, it has no side effects
future.cancel(true);
}


  1. 当任务不响应中断信号时。假设任务执行套接字I/O,不响应中断信号,因此使用上述方法将不会中止任务,future将超时,但取消finally块将没有影响,线程将继续侦听套接字。如果由pool实现,我们可以关闭套接字或在连接时调用close方法。
public interface CustomCallable < T > extends Callable < T > {
void cancel();
RunnableFuture < T > newTask();
}


public class CustomExecutorPool extends ThreadPoolExecutor {
protected < T > RunnableFuture < T > newTaskFor(Callable < T > callable) {
if (callable instanceof CancellableTask)
return ((CancellableTask < T > ) callable).newTask();
else
return super.newTaskFor(callable);
}
}


public abstract class UnblockingIOTask < T > implements CustomCallable < T > {
public synchronized void cancel() {
try {
obj.close();
} catch (IOException e) {
logger.error("io exception", e);
}
}


public RunnableFuture < T > newTask() {
return new FutureTask < T > (this) {
public boolean cancel(boolean mayInterruptIfRunning) {
try {
this.cancel();
} finally {
return super.cancel(mayInterruptIfRunning);
}
}


};
}
}

在用Java开发了15年之后,有一件事我想对世界说。

弃用Thread.stop()和所有反对其使用的神圣之战只是另一个坏习惯或设计缺陷不幸地成为现实……(如。想讨论Serializable接口吗?)

争论的焦点在于,杀死线程会使对象处于不一致的状态。所以呢?欢迎来到多线程编程。你是一个程序员,你需要知道你在做什么,是的。杀死线程会使对象处于不一致状态。如果你担心它,使用flag并让线程优雅地退出;但有很多时候,我们没有理由担心。

但没有. .如果你输入thread.stop(),你很可能会被所有查看/注释/使用你代码的人杀死。所以你必须使用flag,调用interrupt(),在你的代码周围放置if(!flag),因为你根本没有循环,最后祈祷,你用来做外部调用的第三方库是正确编写的,并且没有不正确地处理InterruptException