如何优雅地停止一个java线程?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/3194545/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-13 17:17:02  来源:igfitidea点击:

How to stop a java thread gracefully?

javamultithreading

提问by User 1034

I wrote a thread, it is taking too much time to execute and it seems it is not completely done. I want to stop the thread gracefully. Any help ?

我写了一个线程,执行时间太长,似乎还没有完全完成。我想优雅地停止线程。有什么帮助吗?

采纳答案by Hyman

The goodway to do it is to have the run()of the Thread guarded by a booleanvariable and set it to truefrom the outside when you want to stop it, something like:

这样做的方法是让run()Thread 由一个boolean变量保护,并true在您想要停止它时将其设置为从外部,例如:

class MyThread extends Thread
{
  volatile boolean finished = false;

  public void stopMe()
  {
    finished = true;
  }

  public void run()
  {
    while (!finished)
    {
      //do dirty work
    }
  }
}

Once upon a time a stop()method existed but as the documentation states

曾几何时stop()存在一种方法,但正如文档所述

This method is inherently unsafe. Stopping a thread with Thread.stop causes it to unlock all of the monitors that it has locked (as a natural consequence of the unchecked ThreadDeath exception propagating up the stack). If any of the objects previously protected by these monitors were in an inconsistent state, the damaged objects become visible to other threads, potentially resulting in arbitrary behavior.

这种方法本质上是不安全的。使用 Thread.stop 停止线程会使其解锁所有已锁定的监视器(这是未经检查的 ThreadDeath 异常向上传播堆栈的自然结果)。如果先前受这些监视器保护的任何对象处于不一致状态,则损坏的对象将对其他线程可见,从而可能导致任意行为。

That's why you should have a guard..

这就是为什么你应该有一个守卫..

回答by Bart van Heukelom

Make a volatile boolean stopsomewhere. Then in the code that runs in the thread, regularly do

stop某处创建一个 volatile 布尔值。然后在线程中运行的代码中,定期做

 if (stop) // end gracefully by breaking out of loop or whatever

To stop the thread, set stopto true.

要停止线程,请设置stoptrue

I think you must do it manually this way. After all, only the code running in the thread has any idea what is and isn't graceful.

我认为您必须以这种方式手动完成。毕竟,只有在线程中运行的代码才知道什么是优雅的,什么是不优雅的。

回答by Xorty

You should not kill Thread from other one. It's considered as fairly bad habit. However, there are many ways. You can use returnstatement from thread's runmethod. Or you can check if thread has already been interrupted and then it will cancel it's work. F.e. :

你不应该从其他人那里杀死 Thread。这被认为是相当坏的习惯。但是,有很多方法。您可以使用return线程run方法中的语句。或者你可以检查线程是否已经被中断,然后它会取消它的工作。铁 :

while (!isInterrupted()) { 
  // doStuff
}

回答by Andreas Dolk

You need to send a stop-message to the Thread and the Thread itself needs to take action if the message has been received. This is pretty easy, if the long-running action is inside loop:

您需要向 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
     }
   }
}

回答by Nathan Hughes

The bad part about using a flag to stop your thread is that if the thread is waiting or sleeping then you have to wait for it to finish waiting/sleeping. If you call the interrupt method on the thread then that will cause the wait or sleep call to be exited with an InterruptedException.

使用标志来停止线程的坏处是,如果线程正在等待或睡眠,那么您必须等待它完成等待/睡眠。如果您在线程上调用中断方法,那么这将导致等待或睡眠调用以 InterruptedException 退出。

(A second bad part about the flag approach is that most nontrivial code is going to be utilizing libraries like java.util.concurrent, where the classes are specifically designed to use interruption to cancel. Trying to use the hand rolled flag in a task passed into an Executir is going to be awkward.)

(关于标志方法的第二个不好的部分是,大多数重要代码将使用像 java.util.concurrent 这样的库,其中的类专门设计用于使用中断来取消。尝试在传递的任务中使用手动标志进入 Executir 会很尴尬。)

Calling interrupt() also sets an interrupted property that you can use as a flag to check whether to quit (in the event that the thread is not waiting or sleeping).

调用interrupt() 还会设置一个interrupted 属性,您可以将其用作一个标志来检查是否退出(如果线程未在等待或休眠)。

You can write the thread's run method so that the InterruptedException is caught outside whatever looping logic the thread is doing, or you can catch the exception within the loop and close to the call throwing the exception, setting the interrupt flag inside the catch block for the InterruptedException so that the thread doesn't lose track of the fact that it was interrupted. The interrupted thread can still keep control and finish processing on its own terms.

您可以编写线程的 run 方法,以便在线程正在执行的任何循环逻辑之外捕获 InterruptedException,或者您可以在循环内捕获异常并关闭抛出异常的调用,在 catch 块内为InterruptedException 以便线程不会忘记它被中断的事实。被中断的线程仍然可以保持控制并按照自己的方式完成处理。

Say I want to write a worker thread that does work in increments, where there's a sleep in the middle for some reason, and I don't want quitting the sleep to make processing quit without doing the remaining work for that increment, I only want it to quit if it is in-between increments:

假设我想编写一个以增量方式工作的工作线程,由于某种原因,中间有一个睡眠,我不想退出睡眠以使处理退出而不为该增量做剩余的工作,我只想要如果它介于增量之间,则退出:

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();
        }
    }
}

Here is an answer to a similar question, including example code.

这是对类似问题的回答,包括示例代码。

回答by PoweredByRice

For a thread to stop itself, no one seems to have mentioned (mis)using exception:

对于一个线程停止自身,似乎没有人提到(错误)使用异常:

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 {};

}

A subclass just need to override doRun() normally as you would with a Thread, and call stopSelf() whenever it feels like it wants to stop. IMO it feels cleaner than using a flag in a while loop.

子类只需要像使用线程一样正常覆盖 doRun() ,并在感觉想要停止时调用 stopSelf() 。IMO 感觉比在 while 循环中使用标志更干净。