我创建了一个多线程应用程序,它使用相同的ScheduledExecutorService(方法scheduleAtFixedRate和一个固定的10个线程的线程池)执行不同的任务。然而,除了一个主要任务之外的所有线程(不要与主线程混淆!)大部分时间都在睡觉,直到有用户输入。主任务和其他(用户输入)线程之间共享的数据受同步块中的锁对象保护。Java ScheduledExecutorService - 需要关于实时性能问题的建议
主要任务以相当大的频率执行重复任务,例如25赫兹(即40毫秒的周期),重要的是及时执行此任务。通常情况也是如此,但不幸的是并非全部。其他“很好”的应用程序也运行在同一台计算机上(Linux OP),但是CPU 100%运行在100%以上。在60分钟的测量期间(即90000个样品),在约50个样品中,两个连续样品之间的实际周期>≥60ms,并且其中约30个周期超过100ms,在几个非常差的病例(时间相当接近,以秒为单位),时间在1000到2300毫秒之间。在测量过程中没有用户输入。看看数据日志,看起来很明显,有些东西阻止执行程序在这些时间间隔内执行其工作,因为它们通常跟着执行程序的“追赶”,即在2或3毫秒内从应用程序中获取多个日志。
我已经尝试过在每次执行任务时定期进行垃圾回收,但是(至少从短期来看)它似乎只会让事情变得更糟。我也测量了任务的执行时间。它大部分是大约1毫秒,它不应该导致执行器崩溃(或者应该这样做?)。在这里也有的偏差,偶尔也会在100ms左右,但他们可以解释不到50%的延迟。我试过寻找TaskRejectedExceptions,什么都没发现。
所以我现在的问题基本上是:我可以期待从一个ScheduledExecutorService随着时间的推移?这可能是一个线程问题,尽管在这些情况下只有主要任务应该运行吗?什么可能会导致ScheduledExecutor暂时停止执行,只能用它的“追赶”数据来洪泛日志,并且是否有任何方法来控制这种恼人的行为?这可能与我的JVM仅仅是没有实时优先级功能的普通JVM有关吗?任何关于从哪里开始挖掘的帮助,想法或理论,都会得到真正的赞赏!
我相信你没有通过任务的记录时间来判断任务的执行时间,而是明确地测量并打印出调用之间的时间? – Perception 2012-02-02 22:35:32
这有点令人困惑。所以你所说的测量是两次执行主任务的动作之间的时间,应该每40ms执行一次。 – Tudor 2012-02-02 22:36:19
很难说,但日志和垃圾回收可以大量影响'及时'的性能。要专注于日志记录,您可能不应该在执行程序的某个线程中运行任何日志记录代码。控制GC出现并不在我的联盟中,并且高度依赖于您正在使用的JVM。最好的一般技巧是尽量减少对象的创建,但当GC中断你的应用程序时(除非你精确地定制你的应用程序和JVM设置),*会*得到一个点。 – 2012-02-02 22:39:37