在我正在开发的一个相当复杂的应用程序中,我在一个线程中有以下代码:
long T = System.currentTimeMillis();
Thread.sleep(waitNow);
T = System.currentTimeMillis()-T;
if (T > waitNow*5) {
System.out.println("Overslept "+T+" > "+waitNow);
}
此线程在某些情况下会过度睡眠并产生如下输出:
Overslept 10010 > 10
请注意:我知道Thread.sleep方法的合约允许它睡过头但是这个行为很奇怪,因为过度睡眠的大小(10秒而不是10毫秒)。
线程主要睡眠时间接近指定时间(11-15ms)但是由于某种原因,当应用程序运行时,它会睡得更久(10秒+)并且可能会在几分钟内执行此操作(可能一分钟两到三次。
线程是普通优先级线程。
应用程序中总共有大约35个线程。
我已经使用了jconsole并验证了垃圾收集器在这些睡眠期间没有运行,并且当GC运行时它非常快(jconsole报告它需要大约30-50ms)。
应用程序被分配了256m的内存(-Xmx),但堆没有使用接近该数量(可能大约30米)和一个专门推动VM的内存限制的测试应用程序,并且在同一时间有另一个线程试着睡觉并没有遇到同样的问题。
这个特定的线程发送UDP消息但是它以相对较低的速率发送它们(大约每秒20x 510字节消息--10k / sec)。
线程不会中断,因为它会继续完成计时并打印出关于睡过头的消息。
JRE是1.7.0_45 build 18运行于2013年Retina Macbook pro 13“运行OSX Mavericks。
由于我的测试应用程序在此应用程序同时没有睡过头(实际上测试应用程序根本没有睡过头),这表明它不是时钟更新问题,并且是此应用程序特有的/ JVM然而我无法想到会导致这种情况的任何事情,事实上除了在机器上消耗大量资源之外我无法想到Java中的一个线程会影响另一个线程休眠的时间量。这让我怀疑它在JVM或操作系统中是奇怪的。
问题是:
有谁知道线程睡过头的可能原因是什么?
应用程序(或其他任何东西)可以做什么,不会涉及JVM中使用的高内存或可能影响此问题的机器上的高CPU使用率?
答案 0 :(得分:2)
我的练习中遇到过类似的情况,结果证明JVM safe points存在问题。
对于诊断,您可以使用以下选项:
-XX:+PrintGCApplicationStoppedTime
- 它打印所有STW暂停,不仅与GC有关-XX:+PrintSafepointStatistics
- 打印安全点详情-XX:PrintSafepointStatisticsCount=1
- 让JVM报告每个安全点就我而言,根本原因在于应用程序代码(可能代码已经触发了JIT中的一些错误)。
答案 1 :(得分:0)
这类问题通常与操作系统有关。这是一个常见问题,有一些工具可以衡量您的日程安排有多糟糕。最值得注意的是http://www.jhiccup.com/然而,5 - 50毫秒的打嗝更为常见。
多秒延迟可能是某些磁盘IO或某些非常严重的问题,例如:也许你的线程正在被交换到磁盘。