[英]How to stop a java thread gracefully?
我写了一个线程,执行时间太长,似乎还没有完全完成。 我想优雅地停止线程。 有什么帮助吗?
这样做的好方法是让 Thread 的run()
由一个boolean
变量保护,并在您想要停止它时从外部将其设置为true
,例如:
class MyThread extends Thread
{
volatile boolean finished = false;
public void stopMe()
{
finished = true;
}
public void run()
{
while (!finished)
{
//do dirty work
}
}
}
曾几何时存在stop()
方法,但正如文档所述
这种方法本质上是不安全的。 使用 Thread.stop 停止线程会使其解锁所有已锁定的监视器(这是未经检查的 ThreadDeath 异常向上传播堆栈的自然结果)。 如果先前受这些监视器保护的任何对象处于不一致状态,则损坏的对象将对其他线程可见,从而可能导致任意行为。
这就是为什么你应该有一个守卫..
使用标志来停止线程的坏处是,如果线程正在等待或睡眠,那么您必须等待它完成等待/睡眠。 如果您在线程上调用中断方法,那么这将导致等待或睡眠调用以 InterruptedException 退出。
(关于标志方法的第二个不好的部分是,大多数重要代码将使用像 java.util.concurrent 这样的库,其中的类专门设计用于使用中断来取消。尝试在传递的任务中使用手动标志进入 Executor 会很尴尬。)
调用interrupt() 还会设置一个interrupted 属性,您可以将其用作一个标志来检查是否退出(如果线程未在等待或休眠)。
您可以编写线程的 run 方法,以便在线程正在执行的任何循环逻辑之外捕获 InterruptedException,或者您可以在循环内捕获异常并关闭抛出异常的调用,在 catch 块内为InterruptedException 以便线程不会忘记它被中断的事实。 被中断的线程仍然可以保持控制并按照自己的方式完成处理。
假设我想编写一个以增量方式工作的工作线程,由于某种原因,中间有一个睡眠,并且我不想退出睡眠以使处理退出而不为该增量做剩余的工作,我只想要如果它介于增量之间,则退出:
class MyThread extends Thread
{
public void run()
{
while (!Thread.currentThread().isInterrupted())
{
doFirstPartOfIncrement();
try {
Thread.sleep(10000L);
} catch (InterruptedException e) {
// restore interrupt flag
Thread.currentThread().interrupt();
}
doSecondPartOfIncrement();
}
}
}
你不应该从其他人那里杀死 Thread。 这被认为是相当坏的习惯。 但是,有很多方法。 您可以使用线程的run
方法中的return
语句。 或者你可以检查线程是否已经被中断,然后它会取消它的工作。 铁 :
while (!isInterrupted()) {
// doStuff
}
使挥发性布尔stop
的地方。 然后在线程中运行的代码中,定期做
if (stop) // end gracefully by breaking out of loop or whatever
要停止线程,请将stop
设置为true
。
我认为您必须以这种方式手动完成。 毕竟,只有在线程中运行的代码才知道什么是优雅的,什么是不优雅的。
您需要向 Thread 发送停止消息,如果收到消息,则 Thread 本身需要采取行动。 如果长时间运行的操作在循环内,这很容易:
public class StoppableThread extends Thread {
private volatile boolean stop = false;
public void stopGracefully() {
stop = true;
}
public void run() {
boolean finished = false;
while (!stop && !finished) {
// long running action - finished will be true once work is done
}
}
}
对于一个线程停止自身,似乎没有人提到(错误)使用异常:
abstract class SelfStoppingThread extends Thread {
@Override
public final void run() {
try {
doRun();
} catch (final Stop stop) {
//optional logging
}
}
abstract void doRun();
protected final void stopSelf() {
throw new Stop();
}
private static final class Stop extends RuntimeException {};
}
子类只需要像使用线程一样正常覆盖 doRun() ,并在感觉想要停止时调用 stopSelf() 。 IMO 感觉比在 while 循环中使用标志更干净。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.