Java 中如何杀死一个线程?
-
21-08-2019 - |
题
你如何杀死一个 java.lang.Thread
在Java中?
解决方案
看到这个 Sun 的帖子解释了他们为何弃用 Thread.stop()
. 。它详细说明了为什么这是一个糟糕的方法以及通常应该采取什么措施来安全地停止线程。
他们推荐的方法是使用共享变量作为要求后台线程停止的标志。然后可以通过请求线程终止的不同对象来设置该变量。
其他提示
在Java中,线程不会被杀死,但是线程的停止是在a中完成的 合作方式. 。线程被要求终止,然后线程可以正常关闭。
经常有一个 volatile boolean
使用该字段,线程定期检查该字段,并在将其设置为相应值时终止。
我 不会 用一个 boolean
检查线程是否应该 终止. 。如果你使用 volatile
作为字段修饰符,这将可靠地工作,但是如果您的代码变得更复杂,则可以使用 for 内部的其他阻塞方法 while
循环,它可能会发生,你的代码会 不终止 完全或至少 需要更长的时间 如你所愿。
某些阻塞库方法支持中断。
每个线程已经有一个布尔标志 中断状态 你应该利用它。可以这样实现:
public void run() {
try {
while (!interrupted()) {
// ...
}
} catch (InterruptedException consumed)
/* Allow thread to exit */
}
}
public void cancel() { interrupt(); }
源码改编自 Java 并发实践. 。自从 cancel()
方法是公共的,您可以让另一个线程根据需要调用此方法。
一种方法是设置一个类变量并将其用作哨兵。
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 以“杀死”线程。
有一种方法可以做到这一点。但如果你必须使用它,要么你是一个糟糕的程序员,要么你正在使用由糟糕的程序员编写的代码。所以,你应该考虑停止成为一个糟糕的程序员或停止使用这些糟糕的代码。此解决方案仅适用于没有其他办法的情况。
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() );
我想根据积累的评论添加一些观察结果。
- 如果安全管理器允许,Thread.stop() 将停止线程。
- Thread.stop() 是危险的。话虽如此,如果您在 JEE 环境中工作并且无法控制被调用的代码,那么这可能是必要的。
- 您永远不应该停止容器工作线程。如果您想运行容易挂起的代码,请(小心地)启动一个新的守护线程并监视它,必要时终止它。
- stop() 会创建一个新的 ThreadDeath 错误 呼叫 线程,然后导致该错误被应用到 目标 线。因此,堆栈跟踪通常毫无价值。
- 在 JRE 6 中,stop() 与安全管理器进行检查,然后调用 stop1(),stop1() 又调用 stop0()。stop0() 是本机代码。
我会投票给 Thread.stop()
.
例如,您有一个持久的操作(如网络请求)。假设您正在等待响应,但这可能需要一些时间,并且用户导航到其他 UI。这个等待线程现在是a)无用的b)潜在的问题,因为当他得到结果时,它是完全无用的,他将触发可能导致许多错误的回调。
所有这些,他都可以进行 CPU 密集型响应处理。而你,作为一名开发人员,甚至无法阻止它,因为你无法抛出 if (Thread.currentThread().isInterrupted())
所有代码中的行。
所以无法强行停止线程很奇怪。
问题比较模糊。如果您的意思是“我如何编写一个程序,以便线程在我想要的时候停止运行”,那么其他各种响应应该会有所帮助。但是,如果您的意思是“我的服务器出现紧急情况,我现在无法重新启动,我只需要一个特定的线程死掉,发生什么情况”,那么您需要一个干预工具来匹配监控工具,例如 jstack
.
为此我创建了 jkill线程. 。请参阅其使用说明。
当然,在某些情况下,您正在运行某种不完全受信任的代码。(我个人通过允许上传的脚本在我的 Java 环境中执行来实现这一点。是的,安全警钟随处响起,但它是应用程序的一部分。)在这种不幸的情况下,您首先只是希望脚本编写者尊重某种布尔运行/不运行信号。唯一合适的故障安全措施是,如果线程运行时间超过某个超时时间,则调用线程上的 stop 方法。
但是,这只是“体面”,而不是绝对的,因为代码可以捕获 ThreadDeath 错误(或您显式抛出的任何异常),而不是像绅士线程应该做的那样重新抛出它。所以,最重要的是 AFAIA 没有绝对的安全保障。
没有办法优雅地终止一个线程。
您可以尝试中断线程,一种常见的策略是使用毒丸向线程发送消息以使其自行停止
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”);
一般来说,你不会杀死、停止或中断一个线程(或检查它是否被interrupted()),而是让它自然终止。
很简单。您可以在 run() 方法中将任何循环与(易失性)布尔变量一起使用来控制线程的活动。您还可以从活动线程返回到主线程来停止它。
这样你就可以优雅地杀死一个线程:)。
尝试突然终止线程是众所周知的不良编程实践,也是不良应用程序设计的证据。多线程应用程序中的所有线程显式和隐式共享相同的进程状态,并强制彼此合作以保持一致,否则您的应用程序将容易出现难以诊断的错误。因此,开发人员有责任通过仔细而清晰的应用程序设计来保证这种一致性。
对于受控线程终止,主要有两种正确的解决方案:
- 使用共享易失性标志
- 使用 Thread.interrupt() 和 Thread.interrupted() 方法对。
可以在这里找到与线程突然终止相关的问题的详细解释以及受控线程终止的错误和正确解决方案的示例:
“杀死线程”并不是正确的用语。这是我们可以实现线程优雅完成/退出的一种方法:
我使用的可运行:
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");
}
}
我没有让中断在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;
}