如何在Java中终止一个java.lang.Thread
?
请看Sun关于为什么废弃Thread.stop()
的线程讨论。它详细说明了为什么这是一种不好的方法以及通常应该采取什么措施来安全地停止线程。
他们推荐的方法是使用共享变量作为标志,要求后台线程停止。然后可以由请求线程终止的不同对象设置此变量。
java.sql.DriverManager
中的方法getConnection()
。如果连接尝试时间过长,我会尝试通过调用Thread.interrupt()
来终止相应的线程,但它并不影响线程。然而,Thread.stop()
可以工作,尽管Oracle表示如果interrupt()
无法工作,则不应该使用它。我想知道如何使其工作并避免使用已弃用的方法。 - Danny Lo通常情况下,您不需要主动去打断正在进行的操作。如果需要打断操作,可以使用Thread.interrupt()(javadoc链接)
为什么要这样做的一个很好的解释在此(Java技术笔记链接)
interrupt()
方法时,线程上下文会发生什么?主要问题与每个新线程的日志生成有关。 - ABcDexter在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()
方法是公开的,你可以让另一个线程调用该方法来实现你的目的。
一种方法是设置一个类变量并将其用作标志。
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以“终止”线程。
volatile
,以确保它在任何地方都能正常工作。内部类不是静态的,因此标志应该是实例变量。应该在访问器方法中清除标志,以便执行其他操作(如中断)。名称“flag”不具描述性。 - erickson根据已经累积的评论,我想添加几个观察结果。
Thread.stop()
会停止一个线程,但前提是安全管理器允许该操作。Thread.stop()
是危险的。尽管如此,在JEE环境下,如果您无法控制被调用的代码,则可能是必需的;请参见为什么Thread.stop被弃用?stop()
在调用线程上创建一个新的ThreadDeathError
错误,然后在目标线程上抛出该错误。因此,堆栈跟踪通常是无用的。stop()
会与安全管理器进行检查,然后调用stop1()
再调用stop0()
。 stop0()
是本地代码。Thread.stop()
尚未被移除,但在Java 11中移除了Thread.stop(Throwable)
。(邮件列表,JDK-8204243)有一种方法可以做到这一点。但是,如果你不得不使用它,那么要么你是个糟糕的程序员,要么你正在使用由糟糕的程序员编写的代码。因此,你应该考虑停止成为一个糟糕的程序员或停止使用这个糟糕的代码。 这个解决方案仅适用于没有其他方法的情况。
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
。 - LiiThread.stop
的功能与之相同,但它还会检查访问和权限。
使用Thread.stop
是相当明显的,我不记得为什么我使用Thread.stop0
而不是它。也许Thread.stop
在我的特殊情况下(Java 6上的Weblogic)无法正常工作。或者可能是因为Thread.stop
已被弃用并引发警告。 - VadimPlatonov我会选择使用Thread.stop()
方法。
例如,如果您有一个长时间运行的操作(比如一个网络请求)。 假设您正在等待响应,但是它可能需要一段时间而且用户已经导航到其他UI上。 这个等待线程现在是a)无用的b)潜在问题,因为当它获得结果时,它完全是无用的,并且将触发可以导致许多错误的回调。
所有这些都可以进行CPU密集型的响应处理。而作为开发人员,您甚至无法停止它,因为您不能在所有代码中抛出if (Thread.currentThread().isInterrupted())
。
所以无法强制停止线程是很奇怪的。
Thread.stop()
。你不是在投票支持 Thread.stop()
,而是要求每个实现可能需要长时间才能完成的操作的人将其变得可以安全地中止。这可能是一个好主意,但与实现 Thread.stop()
作为请求安全中止的方式无关。我们已经有了 interrupt
。 - David Schwartzstop
更糟糕。" - Stephen Cjstack
。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环境中执行来实现这一点。是的,安全警报响遍了整个应用程序,但这是应用程序的一部分。)在这种不幸的情况下,你首先只是希望通过要求脚本编写者尊重某种布尔值的运行/不运行信号来解决问题。你唯一的体面备选方案是,在线程运行时间超过某个超时时间后调用线程的停止方法。
但是,这只是“体面”,而不是绝对的,因为代码可能会捕获ThreadDeath错误(或任何你明确抛出的异常),并且不像一个有礼貌的线程应该做的那样重新抛出它。所以,归根结底,据我所知没有绝对的备选方案。
ExecutorStatus
答案:https://dev59.com/IHE95IYBdhLWcg3wheRR - Kirby