Java线程中的大量过睡会在没有GC干扰和低机器负载的情况下发生

时间:2013-12-02 20:42:38

标签: java multithreading concurrency garbage-collection udp

在我正在开发的一个相当复杂的应用程序中,我在一个线程中有以下代码:

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使用率?

2 个答案:

答案 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或某些非常严重的问题,例如:也许你的线程正在被交换到磁盘。