当有等待线程时如何优雅地降级程序?

发布于 2024-12-21 23:38:41 字数 390 浏览 4 评论 0原文

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

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

   public void stop() {
      stop = true;
   }

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

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

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

I know the construct of terminating a thread gracefully:

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

   public void stop() {
      stop = true;
   }

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

But if some thread is waiting for something, inside some object (using wait(), without time limit), then this construct won't be useful to stopping this thread, because he is already past the condition in the while loop, so he will continue forever.

So, what is the right way to stop the waiting threads?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

许一世地老天荒 2024-12-28 23:38:41

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

如果您正在等待某些事情,我假设您必须捕获 InterruptedException,不是吗?

If the Thread is actually waiting for something, you should call the method Thread.interrupt() to interrupt the thread. Instead of checking for your custom variable in the while loop, use Thread.isInterrupted() or Thread.interrupted() - one resets the interruption flag, the other doesn't.

If you are waiting on something, I assumed you had to catch the InterruptedException, didn't you?

不语却知心 2024-12-28 23:38:41

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

If you don't want your threads to wait indefinitely, don't code them to do that in the first place. You're writing their code, so write it to do what you actually so you don't have to try to fix it from the outside.

初见你 2024-12-28 23:38:41

每个表现良好的阻塞方法都会声明一个受检查的异常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() (因此中断线程、刷新并关闭文件)。

Every well-behaved blocking method declares a the checked exception InterruptedException, which serves this exact purpose: to notify that the thread has been interrupted while it was blocked.

You have to catch this exception, and actually this could replace your stop field.

For instance, let's consider a logging system that will write messages to a file on a dedicated thread (so that the time spent on IO will not interfere in your application -- assuming it is not IO heavy).

Every thread has an initerrupted flag that can be read through Thread.currentThread().isInterrupted(). You try something like this:

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

Finally, for a graceful shutdown of your application, you must be sure to terminate this thread before letting the JVM shutdown. To do so, you must either be absolutely certain to call stop() before shutting down in any possible way, or you could register a shutdown hook, by adding something like this instance initializer to the class:

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

This will force the JVM to call close() (therefore interrupting the thread, flushing and closing the file) before terminating.

归属感 2024-12-28 23:38:41

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

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

That all depends on why you have to wait in your thread. If the thread is waiting on an uninterruptible IO, then you can take a look at Stop/Interrupt threads blocked on waiting input from socket

Otherwise it all depends on how you wait in the thread. You could use wait(1000), then check for the flag and wait some more. You could wait for a message from a blocking queue, you could use locks/conditions, even wait/notify could work in this case you would need to handle interrupts properly.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文