如何优雅地停止java线程?
我写了一个线程,它花费了太多的时间来执行,似乎还没有完全完成。我想优雅地停止线程。有什么帮助吗?在某个地方创建一个易失性布尔值如何优雅地停止java线程?,java,multithreading,Java,Multithreading,我写了一个线程,它花费了太多的时间来执行,似乎还没有完全完成。我想优雅地停止线程。有什么帮助吗?在某个地方创建一个易失性布尔值stop。然后在线程中运行的代码中,定期执行 if (stop) // end gracefully by breaking out of loop or whatever 要停止线程,请将stop设置为true 我想你必须用这种方式手动操作。毕竟,只有在线程中运行的代码才知道什么是优雅的,什么是不优雅的。最好的方法是让线程的run()由布尔变量保护,并在想要停止时从
stop
。然后在线程中运行的代码中,定期执行
if (stop) // end gracefully by breaking out of loop or whatever
要停止线程,请将stop
设置为true
我想你必须用这种方式手动操作。毕竟,只有在线程中运行的代码才知道什么是优雅的,什么是不优雅的。最好的方法是让线程的run()
由布尔
变量保护,并在想要停止时从外部将其设置为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异常向堆栈上传播的自然结果)。如果以前受这些监视器保护的任何对象处于不一致的状态,则其他线程会看到损坏的对象,从而可能导致任意行为
这就是为什么您应该有一个防护装置。您不应该从另一个防护装置杀死线程。这被认为是相当坏的习惯。然而,有很多方法。您可以使用线程的
run
方法中的return
语句。
或者您可以检查线程是否已经被中断,然后它将取消它的工作。F.e.:
while (!isInterrupted()) {
// doStuff
}
您需要向线程发送一条停止消息,如果收到消息,线程本身需要采取行动。如果长时间运行的操作在循环内,那么这非常容易:
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
}
}
}
使用标志停止线程的坏处在于,如果线程正在等待或休眠,则必须等待它完成等待/休眠。如果您在线程上调用中断方法,那么这将导致等待或睡眠调用以InterruptedException退出 (标志方法的第二个缺点是,大多数非平凡代码将使用java.util.concurrent之类的库,这些库中的类专门设计为使用中断来取消。在传递给执行器的任务中尝试使用手动标志会很尴尬。) 调用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();
}
}
}
对于要停止自身的线程,似乎没有人提到(mis)使用异常:
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()。在我看来,这比在while循环中使用标志更干净 请注意,您需要使用锁定或使字段不稳定,以确保读取线程看到来自写入线程的更改。@Jon Skeet:是的,这样会更好。不过出于好奇,如果磁场不波动,停止时间大约会延迟多久?@Bart:在实践中,可能一点也不长。理论上,永远。@Jon Skeet:真的吗?这难道不意味着在理论上正确的多线程程序中,许多字段都需要是可变的吗?当我有机会时,我还需要进一步阅读。@Bart:使用非易失性布尔值,以下while(!stopped){doStuff();}循环可以优化为if(!stopped)return;而(true){doStuff();}由编译器执行者Jon Skeet对Bart的答案的评论——这也适用于您的答案。如果在您执行“脏工作”线程时“完成”的更改不会结束,那么您必须进行定期检查,例如在循环中有一个睡眠(x),这是不推荐的,并且会给您带来糟糕的性能,那么这真的是一个好方法吗?我们正在谈论优雅地退出线程。强制线程在其肮脏的工作过程中退出并不是一种优雅的方式。除非有特定的中断原因,否则您应该一直等待下一次迭代。您可以使用wait和notify避免显式循环检查这已经使内置的INTERRUP()和isInterrupted()方法加倍。run方法为void,它不能返回任何内容。您可以使用带有void返回类型的空return语句,方法将结束这与第一个答案类似,只是使用return而不是简单地让run()方法退出。是的,你可以使用return;这将从一个空洞的方法中退出啊,我误解了。我以为您想从运行中返回一个值,并用它做一些事情(无论什么)。当然,使用return退出这个方法是完全可能的。我编辑了我的答案,但会去看看,为什么它适用于这里-在你的答案中,我想,它必须是不稳定的,因为你没有提到一个方法,它看起来像,必须直接访问
stop
字段。我之前一直想知道volatile关键字(没有尝试宣传我自己的问题:),这里有一些答案:你能解释一下它比使用javainterrupted
标志更好吗?