繁体   English   中英

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

[英]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.

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