有 Java 编程相关的问题?

你可以在下面搜索框中键入要查询的问题!

java如何维护持久的后台线程?

摘要

我有一个应该长期运行的服务器,它为IO生成了一些后台线程。我试图确保后台/IO线程不会停止运行,或者如果它们停止运行,它们将被重新启动

当前解决方案

目前,我的主循环只检查所有背景检查的状态(下面的伪代码)。我认为应该有更好的办法

while (!Thread.currentThread().isInterrupted()) {
    maintainThreads();
    doWork();
    condition.await(30, TimeUnit.SECONDS);
}

我的尝试

我正在考虑切换到一个SingleThreadExecutor,带有一个自定义的queue,当它拉取下一个任务时不会删除Runnable。然后executor将为我管理线程,以便我可以将其从主循环中取出

我担心每个线程有一个执行器会对性能造成影响,而且对于这个问题有更简单/更好的解决方案。我还考虑为每个线程设置关机挂钩,让它们自己重新启动

任何帮助都将不胜感激


共 (3) 个答案

  1. # 1 楼答案

    对于应用程序,进程(而不是线程)重新创建/重新启动是最可靠的故障恢复方法

    真正的任务关键型系统如何处理故障?通过提供冗余、心跳监测、快速切换等功能

    不要盲目地试图保留已经失败的线程。有许多原因可以破坏我们的进程,而我们(人类)只知道其中的一些原因

    如果我们快速失败并重新启动进程,操作系统内核将确保我们清除初始状态。所以,即使我们的程序不太可靠,程序也会在一定时间内运行并完成任务

  2. # 2 楼答案

    这里真正的问题是你所说的“下降”或者如果他们下降,他们会被带回来。”

    据我所知,只有两种方式可以使线程运行,而不必在java中退出整个进程:

    1. run()方法终止,或者通过异常终止,或者完成run方法正常地(即非异常地)
    2. ^在线程上调用{}

    让我们先来讨论一下(2)-Thread.stop()已被弃用,在任何性能良好的应用程序中都是一个大禁忌。你几乎可以假设它不会被调用,因为如果它被调用,你的application is already badly broken。此时重新启动任何线程可能会产生未定义的影响,因为应用程序的状态不一致

    那么对于(1),您只需确保run()不会终止。它通常不会终止,因为您已经设置了一个无限循环。为了防止异常终止,您可以catch (Throwable t)并保持循环(在适当地记录错误之后)

    当然,一个catch (Throwable t)如果没有后续的重写,通常是一种代码气味。这意味着您遇到了一些未指明的错误,然后决定继续前进。错误的范围可能从良性(例如,远程客户端断开连接导致的SockedClosedExcpetion)到不可恢复(例如OutOfMemoryError或更糟的情况)。你真的应该问问自己,如果遇到任何类型的异常,你是否希望这个线程继续

    您的应用程序可能处于无效状态,无法继续。一种折衷方法是只捕获Exception的子类,并在Error上终止应用程序。一种更保守的方法是在您不知道如何处理的任何类型的异常上终止应用程序(并将其视为待修复的bug)

  3. # 3 楼答案

    维护持久后台线程的一个重要部分是在线程级别正确处理异常。在处理错误条件,尤其是顶级服务器/守护程序代码中的异常时,您需要记住,某些异常无法处理!当遇到这样的异常时,您应该立即退出,或者尝试尽可能多地清理,然后退出

    例如,大多数类型错误的异常都不应该被处理。这包括java。lang.VirtualMachineeError异常:InternalError、OutOfMemoryError、StackOverflowerError、UnknownError等。正如前面的回答所提到的,捕获Throwable是一个大问题,因为许多异常无法恢复。想想你的失败策略——当失败有意义时,在这种情况下你能做什么(可能是记录错误,或者向用户显示消息)

    尝试总是正确地处理InterruptedException,因为它给了您清理和优雅地关闭线程的时间。否则,您将面临数据损坏的风险

    有关更多异常处理技巧,请查看我的Exceptions Guidelines帖子