编写应该“永远”运行的java程序时要考虑的事项

2022-09-04 21:26:14

我必须编写一个被认为“永远”运行的程序,这意味着它不会定期终止。到目前为止,我总是编写程序,这些程序将在一天结束时运行并终止。程序必须执行一些同步,暂停 n 分钟,然后再次同步。

AFAIK我目前的实现应该没有问题,理论上它应该运行良好,但我缺乏任何实际经验。

那么,是否有任何“模式”或最佳实践来编写具有非常长运行时间的非常健壮且资源高效的java程序?例如,在一个月/一年的运行时之后,可能出现哪些问题?

一些背景:

  • Java:1.7,但编译到1.5
  • 操作系统:Windows(确切的版本尚不确定)

提前致谢


答案 1

只是我在编写此类应用程序时必须记住的所有事情的大脑转储。

避免内存泄漏

我有一个应用程序,每天中午运行一次,其中我有一个.我没有正确地关闭它,然后我们开始想知道为什么我们的虚拟机会在几周后崩溃。内存泄漏可以以 anyhing 的形式出现,最常见的例子之一是你没有适当地放置对象。例如,使用类的字段作为临时存储的方法。通常,该类会持续存在,引用也会持续存在。这让你带着物体,坐在记忆中,什么都不做。FileWriterde-reference

使用正确类型的调度程序

我在该应用程序中使用了java,后来我了解到,当另一个应用程序更改系统时钟时,最好使用AdventdThreadPoolExecutor。因此,如果您打算完全基于Java,我强烈建议您使用计时器,以解决本问题中详述的所有原因。Timer

注意内存使用情况和环境

如果你的应用每天加载大量数据,并且你在同一台服务器上运行其他应用,则可能需要注意时间安排。例如,假设在中午,三个应用程序运行其计划的操作,我会说在任何其他时间运行它可能是一个明智的举动。请注意执行代码的环境。

错误处理

你可能想要配置你的应用,以便在应用发生故障的情况下让你知道是否出现问题。如果它每隔几个小时在某个时间运行一次,这意味着人们可能依赖于它,所以我会在你的Java代码中有一个函数,向你发送一封电子邮件,详细说明异常的性质。

使其可配置

同样,如果它需要在一天中的不同时间点运行,你不希望必须将它拉下来几个小时来对代码进行一些小的更改。相反,将其移植到java属性文件或XML配置(或者实际上,其他任何东西)中。这样做的好处是,您可以在任何人真正注意到差异之前更新程序并使其启动并运行。

害怕静态关键字

那个坏男孩会让对象持续存在,即使你破坏了他们的父母参考。它是所有内存泄漏之母,如果你不小心的话。对于常量来说,这很好,你知道的东西不需要改变,需要存在于项目中才能正常运行,但是如果你将其用于项目内的随机值,你很快就会想知道为什么你的应用程序每隔几个小时就会崩溃一次而不是。syncing

道具@X86让我想起了那个。


答案 2

内存泄漏可能是最大的问题。确保在逻辑迭代后没有长期引用。即使是一个相对较小的对象被永远引用,最终也会耗尽内存(更糟糕的是,如果增长率为1GB /月,则在测试期间将更难检测到)。一种可能有帮助的方法是使用探查器的快照功能:在暂停期间拍摄快照,让同步运行几次,然后拍摄另一个快照。比较这些应该显示同步之间的增量,希望它应该为零。

缓存维护是另一个问题。缓存的整体大小需要严格限制(而通常您可以在短期运行的程序中没有缓存,因为所看到的所有内容都足够小,不会导致问题)。同样,正确执行缓存失效也更为重要 - 从广义上讲,在程序仍在运行时,缓存的所有内容都会在某个时候变得陈旧,您需要能够检测到这一点并采取适当的措施。这可能很棘手,具体取决于缓存数据的黄金源的位置。

我要提到的最后一件事是异常处理。对于短期运行的进程,通常只需在遇到异常时让进程死亡就足够了,这样就可以处理问题,并重新运行应用。对于长时间运行的流程,您可能需要比这更具有防御性。考虑在线程中运行程序的各个部分,如果/当线程失败时,可以重新启动*。您可能需要一个 Supervisor 类型的模块,该模块检查其他所有内容是否仍在检测,如果没有,则重新启动它。如果适合您的结构,那么使用actor风格的库而不是Java的标准执行器可以更容易地实现这一点。如果可能的话,您可能希望有钩子(可能通过JMX / MBeans公开)来允许您稍微修改行为,以允许短期黑客/解决方法受到影响,而不必关闭该过程。虽然这需要相当多的远见卓识来准确预测几个月后会出现什么问题......

*或者更确切地说,作业可以在另一个线程中重新启动


推荐