我必须编写一个被认为是“永远”运行的程序,这意味着它不会定期终止。到目前为止,我总是编写将在一天结束时运行并终止的程序。程序必须进行一些同步,暂停 n 分钟而不是再次同步。
AFAIK我当前的实现应该没有问题,理论上应该运行得很好,但我缺乏任何实际经验。
那么有没有“模式”或最佳实践来编写具有很长运行时间的非常强大且资源有效的Java程序?例如,运行一个月/一年之后会出现什么问题?
一些背景知识:
提前致谢
答案 0 :(得分:8)
在撰写此类应用时,我必须记住所有必须记住的事情。
避免内存泄漏
我有一个应用程序,每天中午运行一次,并且我有一个FileWriter
。我没有正确地关闭它,然后我们开始想知道为什么我们的虚拟机在几周之后就会崩溃。内存泄漏确实可以以任何形式出现,其中一个最常见的例子就是你没有恰当de-reference
一个对象。例如,使用类的字段作为临时存储的方法。课程通常会持续存在,参考也是如此。这会让你留下物品,坐在记忆中,什么都不做。
使用正确的计划程序
我在该应用中使用了一个java Timer
,后来我了解到当另一个应用更改系统时钟时,最好使用ScheduledThreadPoolExecutor。因此,如果您计划将其完全保留在Java中,我强烈建议您使用基于Java的this question中详述的所有原因。
请注意内存使用情况和环境
如果您的应用每天都在加载大量数据,而您在同一台服务器上运行其他应用,则可能需要注意时间安排。例如,比如在中午,有三个应用程序运行他们的预定操作,我会说在任何其他时间运行它可能是一个聪明的举动。请注意执行代码的环境。
错误处理
您可能希望配置自己的应用,以便在出现问题时让您知道是否出现问题。如果它每隔几个小时运行一次,这意味着人们可能依赖它,所以我会在你的Java代码中有一个向你发送电子邮件的函数,详细说明异常的性质。
使其可配置
同样,如果它需要在当天的不同时间点运行,那么您不希望将该事情拖了几个小时来对代码进行一些细微的更改。而是将其移植到java Properties文件中,或者移植到XML Config中(或者真的,无论如何)。这样做的好处是,您可以更新您的程序,并在任何人真正注意到差异之前启动并运行它。
要害怕static
关键字
那个坏男孩会使对象持续存在,即使你破坏他们的父引用也是如此。如果你不小心它,它是所有内存泄漏的母亲。对于常量来说这很好,你知道的东西不需要改变并且需要在项目中存在以便运行良好,但是如果你在项目中使用它作为随机值,你会很快想知道为什么你的应用程序每隔几个小时而不是syncing
崩溃。
支持@ X86提醒我那个。
答案 1 :(得分:3)
内存泄漏可能是最大的问题。确保在迭代逻辑后没有长期引用。即使是永远被引用的相对较小的对象,也会耗尽内存最终(更糟糕的是,如果增长率为1GB /月,在测试期间将更难检测到)。一种可能有用的方法是使用分析器的快照功能:在暂停期间拍摄快照,让同步运行几次,然后拍摄另一张快照。比较这些应该显示同步之间的增量,应该有望为零。
缓存维护是另一个问题。缓存的总体大小需要严格限制(通常,您可以在没有短期运行程序的情况下离开,因为所看到的一切都会小到不会导致问题)。同样地,正确执行缓存失效更为重要 - 一般来说,在程序仍在运行时,缓存的所有内容将在某些时候变得陈旧,并且您需要能够检测到并采取适当的措施行动。这可能很棘手,具体取决于缓存数据的黄金来源。
我要提到的最后一件事是异常处理。对于短时间运行的进程,通常只需在遇到异常时让进程死亡,因此可以解决问题,并重新运行应用程序。通过长时间运行的过程,您可能需要比这更具防御性。考虑在线程中运行程序的一部分,如果/当它们失败时可以重启*。您可能需要一个主管类型的模块,它会检查其他所有内容是否仍然是心跳,如果没有,则重新启动它。如果适合您的结构,使用actor风格的库而不是Java的标准执行程序更容易实现这一点。如果可能的话,您可能希望有一些钩子(可能暴露在JMX / MBean上),这些钩子可以让您稍微修改一下行为,以便在不必降低流程的情况下影响短期黑客攻击/解决方法。虽然这需要相当多的远见来预测几个月内究竟会出现什么问题......
*或者更确切地说,可以在另一个线程中重新启动作业