2

我知道优雅地终止线程的构造:

public class Foo implements Runnable {
   private volatile boolean stop = false;

   public void stop() {
      stop = true;
   }

   public void run() {
      while (!stop) {
         ...
      }
   }
}

但是,如果某个线程在某个对象内等待某些东西(使用wait(),没有时间限制),那么这个构造对于停止这个线程将没有用,因为他已经超过了 while 循环中的条件,所以他将永远继续.

那么,停止等待线程的正确方法是什么?

4

4 回答 4

2

如果您不希望您的线程无限期地等待,请不要首先编写代码来执行此操作。你正在编写他们的代码,所以编写它来做你实际的事情,这样你就不必尝试从外部修复它。

于 2011-12-21T01:03:04.620 回答
2

如果线程实际上在等待什么,你应该调用方法Thread.interrupt()来中断线程。不要在 while 循环中检查您的自定义变量,而是使用 Thread.isInterrupted() 或 Thread.interrupted() - 一个重置中断标志,另一个不重置。

如果您正在等待某事,我认为您必须捕获InterruptedException,不是吗?

于 2011-12-21T02:57:00.923 回答
1

每个行为良好的阻塞方法都声明了一个已检查异常InterruptedException,这正是服务于这个目的:通知线程在被阻塞时已被中断。

您必须捕获此异常,实际上这可能会替换您的stop字段。

例如,让我们考虑一个日志系统,它将消息写入专用线程上的文件(这样在 IO 上花费的时间不会干扰您的应用程序——假设它不是 IO 繁重的)。

每个线程都有一个可以读取的中断标志Thread.currentThread().isInterrupted()。你尝试这样的事情:

class Logger {
  private final File file = ...;
  private final BlockingQueue<String> logLines = new LinkedBlockingQueue<String>();
  private final Thread loggingThread = new Thread(new Runnable(){
    @Override public void run() {
      PrintWriter pw;
      try {
        pw = new PrintWriter(new BufferedOutputStream(new FileOutputStream(file)));
        while (!Thread.currentThread().isInterrupted()) {
          try {
            pw.println(logLines.take());
          } catch (InterruptedException e) {
            Thread.currentThread().interrupt(); // good habit: make sure the interrupt status is set
          }
        }
        pw.flush();
        pw.close();
      } catch (IOException e) { ... flush and close pw if not null and open ... }
    }
  });
  { loggingThread.start(); }
  public void log(final String line) { logLines.offer(line); } // will always work, because logLines is a LinkedBQ.
  public void stop() { loggingThread.interrupt(); }
}

最后,为了让您的应用程序正常关闭,您必须确保在让 JVM 关闭之前终止该线程。为此,您必须绝对确定stop()在以任何可能的方式关闭之前调用,或者您可以通过向类添加类似此实例初始化程序的内容来注册关闭挂钩:

class Logger {
  ...
  {
    Runtime.getRuntime().addShutdownHook(new Thread(new Runnable() {
      @Override public void run() { close(); }
    }));
  }
}

这将强制 JVM 在终止之前调用 close() (因此中断线程、刷新和关闭文件)。

于 2011-12-22T04:35:34.160 回答
0

这一切都取决于你为什么必须在你的线程中等待。如果线程正在等待不可中断的 IO,那么您可以查看在等待来自套接字的输入时阻塞的停止/中断线程

否则,这一切都取决于您在线程中的等待方式。您可以使用wait(1000),然后检查标志并等待更多时间。您可以等待来自阻塞队列的消息,您可以使用锁/条件,甚至wait/notify可以在这种情况下工作,您需要正确处理中断。

于 2011-12-21T01:40:38.673 回答