【问题标题】:How to make sure a long running Java thread never die如何确保长时间运行的 Java 线程永不死亡
【发布时间】:2020-01-24 02:36:52
【问题描述】:

我有一个长时间运行的线程来执行管理任务。鉴于系统不会立即受到影响,因此很难检测到线程的故障。我想确保这个线程永远不会消失。我的理解是只要代码捕捉到所有东西(Throwable),它就永远不会死。下面是示例代码:

while (true) {
    try {
        // house keeping logic
    } catch (Throwable t) {
        // do not do anything
    }
}

我的理解正确吗?有没有更好的方法来托管长时间运行的后台任务?我知道 ScheduledExecutorService 可以定期安排任务,但是如果任务需要继续检查某些资源,那么将所有内容放在一个 while 循环中可能会更有效。

【问题讨论】:

  • 在少数情况下线程会与整个JVM一起死掉(例如OutOfMemoryError);不存在不朽的过程。这取决于资源,但将所有内容放在 while 循环中几乎肯定不是最有效的方式。
  • 这个线程运行在什么样的应用程序中?

标签: java multithreading exception


【解决方案1】:

你不能保证长时间运行的线程。但是,如果您的线程出现问题,您可以重新生成逻辑。

你可以做的是有一个观察者来检查线程是否每 x 分钟运行一次。

请注意,如果 JVM 关闭或崩溃,watcher 将失败。如果你想在JVM关闭的情况下重新启动线程,你需要有外部监控。为此,您可以使用supervisord.等工具

public class LongRunningThread extends Thread {
    private volatile boolean IS_RUNNING = true;

    @Override
    public void run() {
        while (IS_RUNNING) {
            try {
                // actions
                this.houseKeep();
            } catch (Exception e) {
            }
        }
    }

    private void houseKeep() {
        // housekeeping logic here
    }

}

class ThreadWatcher {
    private Thread threadToBeWatched;

    public ThreadWatcher(Thread threadToBeWatched) {
        this.threadToBeWatched = threadToBeWatched;
    }

    @Scheduled(cron = "*/1 * * * *")
    public void checkStatus() {
        if (!threadToBeWatched.isAlive()) {
            // Logic to restart the thread.
        }
    }
}

【讨论】:

    【解决方案2】:

    如果管家逻辑包括一些可以归类为周期性任务的任务(例如,每 20 秒检查一次与某些服务的连接)-那么你最好使用TimerTask

    一些example could be of help

    如果在 TimerTask 中发生了某些事情(除了 OOM 之外的任何事情) - 它不会影响负责任务调度的计时器。

    【讨论】:

      【解决方案3】:

      几点:

      我强烈建议使用 ScheduledExecutorService 或您正在使用的任何工具或框架可能提供的其他等效功能(例如 Spring 中的 @Scheduled)。在这些情况下,有很多注意事项不是立即显而易见的,一个完善且维护良好的库将处理这些问题。

      其次,以这种方式轮询更改而没有某种延迟是不常见的。例如,一个典型的场景可能需要您关闭与 1 分钟内没有响应的机器的连接。对于这种循环,您不需要像上面的循环那样经常检查。至少,您应该调用Thread.sleep() 以防止过度使用资源。 (这是ScheduledExecutorService 很好处理的另一个问题。

      最后,您应该包含一些在应用程序终止时优雅地退出循环的方法。类上一个简单的boolean running = true; 就足够了,然后您将循环更改为:while (running) {...}。当你想退出时,只需设置running = false;,你的循环就会退出。

      【讨论】:

      • 捕获所有Throwable 只会捕获已检查的异常 嗯?!
      • 我的错误,显然是深夜。我会编辑我的答案
      猜你喜欢
      • 2023-03-05
      • 2018-02-22
      • 1970-01-01
      • 1970-01-01
      • 2016-07-28
      • 2011-06-15
      • 1970-01-01
      相关资源
      最近更新 更多