简体   繁体   English

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

[英]How to stop a java thread gracefully?

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 ?有什么帮助吗?

The good way to do it is to have the run() of the Thread guarded by a boolean variable and set it to true from the outside when you want to stop it, something like:这样做的方法是让 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
    }
  }
}

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

That's why you should have a guard..这就是为什么你应该有一个守卫..

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

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.您可以编写线程的 run 方法,以便在线程正在执行的任何循环逻辑之外捕获 InterruptedException,或者您可以在循环内捕获异常并关闭抛出异常的调用,在 catch 块内为InterruptedException 以便线程不会忘记它被中断的事实。 The interrupted thread can still keep control and finish processing on its own terms.被中断的线程仍然可以保持控制并按照自己的方式完成处理。

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.这是对类似问题的回答,包括示例代码。

You should not kill Thread from other one.你不应该从其他人那里杀死 Thread。 It's considered as fairly bad habit.这被认为是相当坏的习惯。 However, there are many ways.但是,有很多方法。 You can use return statement from thread's run method.您可以使用线程的run方法中的return语句。 Or you can check if thread has already been interrupted and then it will cancel it's work.或者你可以检查线程是否已经被中断,然后它会取消它的工作。 Fe :铁 :

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

Make a volatile boolean stop somewhere.使挥发性布尔stop的地方。 Then in the code that runs in the thread, regularly do然后在线程中运行的代码中,定期做

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

To stop the thread, set stop to true .要停止线程,请将stop设置为true

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.毕竟,只有在线程中运行的代码才知道什么是优雅的,什么是不优雅的。

You need to send a stop-message to the Thread and the Thread itself needs to take action if the message has been received.您需要向 Thread 发送停止消息,如果收到消息,则 Thread 本身需要采取行动。 This is pretty easy, if the long-running action is inside loop:如果长时间运行的操作在循环内,这很容易:

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

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.子类只需要像使用线程一样正常覆盖 doRun() ,并在感觉想要停止时调用 stopSelf() 。 IMO it feels cleaner than using a flag in a while loop. IMO 感觉比在 while 循环中使用标志更干净。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM