Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/386.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
如何优雅地停止java线程?_Java_Multithreading - Fatal编程技术网

如何优雅地停止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关键字(没有尝试宣传我自己的问题:),这里有一些答案:你能解释一下它比使用java
interrupted
标志更好吗?