摘要
我有一台应该长时间运行的服务器,它会为IO产生一些后台线程。我试图确保后台/ IO线程不会出现故障,或者如果它们确实出现故障,它们会被重新启动。
当前解决方案
目前我的主循环只检查所有后台检查的状态(下面的伪代码)。我认为应该有更好的方法。
while (!Thread.currentThread().isInterrupted()) {
maintainThreads();
doWork();
condition.await(30, TimeUnit.SECONDS);
}
我的尝试
我考虑切换到SingleThreadExecutor
,其中自定义queue
在拉出下一个任务时不会删除Runnable
。然后executor
将为我管理线程,以便我可以将其从主循环中取出。
我担心每个线程都有一个执行程序会受到性能影响,并且存在针对此问题的更简单/更好的解决方案。我还考虑为每个线程设置关闭挂钩,让它们自己重新启动。
任何帮助都将不胜感激。
答案 0 :(得分:1)
这里真正的问题是下来在&#34中的意思;或者如果他们下去他们会被带回来。 "
我知道只有两种方法,一个线程可以关闭,而整个进程本身不会在java中退出:
run()
方法终止,或者通过异常终止,或者通常完成运行方法(即,非例外)。Thread.stop()
。让我们首先解决(2) - Thread.stop()
已被弃用,并且在任何行为良好的应用程序中都是一个很大的禁忌。你几乎可以假设它不会被调用,因为如果它被调用,你的application is already badly broken。此时重新启动任何线程可能具有未定义的效果,因为您的应用程序是不一致的状态。
那么对于(1),你只需要确保run()
没有终止。它不会正常终止 ,因为您已经设置了无限循环。要阻止它以特殊方式终止,您可以catch (Throwable t)
并保持循环(在正确记录错误之后)。
当然,没有后续重新抛出的catch (Throwable t)
通常是代码气味。这意味着你抓住了一些未指明错误的时间,然后决定继续前进。这些错误的范围可能从良性(例如,SockedClosedExcpetion
因为远程客户端断开连接)到不可恢复(例如,OutOfMemoryError
或更糟糕的事情)。您应该问自己是否希望此线程继续面对任何类型的异常。
您的申请可能是无效状态,可能无法继续。一个折衷方案是仅捕获Exception
的子类并终止Error
上的应用程序。更保守的方法是将应用程序终止于您不知道如何处理的任何类型的异常(并将其视为要修复的错误)。
答案 1 :(得分:1)
维护持久性后台线程的一个重要部分是在线程级别正确处理异常。处理错误条件,尤其是顶级服务器/守护程序代码中的异常时,您需要记住,有些异常无法处理!遇到此类异常时,您应立即退出或尝试尽可能多地清理,然后退出。
例如,大多数类型错误的例外都不应该被处理。这包括java.lang.VirtualMachineError异常:InternalError,OutOfMemoryError,StackOverflowError,UnknownError等。正如之前的回答所提到的,捕获Throwable是一个很大的禁忌,因为许多异常都无法恢复。想想你的失败策略 - 什么时候失败才有意义,在这种情况下你能做什么(可能是记录错误,或者向用户显示消息)。
尝试始终正确处理InterruptedException,因为它为您提供了清理并正常关闭线程的时间。否则,您将面临数据损坏的风险。
有关更多异常处理提示,请查看我的Exceptions Guidelines帖子。
答案 2 :(得分:0)
对于应用程序,进程(非线程)重新创建/重新启动是最可靠的故障恢复方法。
真正的关键任务系统如何处理故障?通过提供冗余,心跳监控,快速切换等。
不要试图盲目地保留已经失败的线程。有许多原因可能会对我们的过程造成严重破坏,而我们(人类)只知道其中的一些原因。
如果我们快速失败并重启过程,OS内核确保我们清理初始状态。因此,即使我们的程序不太可靠,程序也会运行并在一定时间内完成工作。