如何优雅地停止java线程?

时间:2010-07-07 12:16:20

标签: java multithreading

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

6 个答案:

答案 0 :(得分:68)

良好的方法是让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异常向上传播的自然结果)。如果先前受这些监视器保护的任何对象处于不一致状态,则受损对象将对其他线程可见,可能导致任意行为。

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

答案 1 :(得分:12)

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

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

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

您可以编写线程的run方法,以便在线程正在执行的任何循环逻辑之外捕获InterruptedException,或者您可以在循环内捕获异常并接近抛出异常的调用,在catch中设置interrupt标志阻止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();
        }
    }
}

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

答案 2 :(得分:10)

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

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

答案 3 :(得分:4)

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

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

要停止该主题,请将stop设置为true

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

答案 4 :(得分:3)

您需要向线程发送停止消息,如果收到消息,则线程本身需要采取措施。如果长时间运行的操作在循环内部,这非常简单:

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

答案 5 :(得分:1)

对于一个自行停止的线程,似乎没有人提到(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 {};

}

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