【发布时间】:2016-05-27 15:24:11
【问题描述】:
我们有一个 Java 应用程序需要在虚拟 (Hyper-V) Windows 2012 R2 服务器上运行,以及其他环境。在此虚拟 Windows 服务器上执行时,它似乎遇到了奇怪的时间问题。我们已经将问题追溯到 Java 调度执行器中的不稳定调度:
public static class TimeRunnable implements Runnable {
private long lastRunAt;
@Override
public void run() {
long now = System.nanoTime();
System.out.println(TimeUnit.NANOSECONDS.toMillis(now - lastRunAt));
lastRunAt = now;
}
}
public static void main(String[] args) {
ScheduledExecutorService exec = Executors.newScheduledThreadPool(1);
exec.scheduleAtFixedRate(new TimeRunnable(), 0, 10, TimeUnit.MILLISECONDS);
}
这段代码应该每 10 毫秒运行一次 TimeRunnable,它会在服务器上产生如下结果:
12
15
2
12
15
0
14
16
2
12
140
0
0
0
0
0
0
0
0
0
0
0
0
1
0
7
15
0
14
16
2
12
15
2
12
1
123
0
0
0
在其他机器上,包括负载很重的虚拟 Linux 机器,以及一些 Windows 桌面,典型的运行如下所示:
9
9
10
9
10
9
10
10
9
10
9
9
10
10
9
9
9
9
10
10
9
9
10
10
9
9
10
9
10
10
10
11
8
9
10
9
10
9
10
10
9
9
9
10
9
9
10
10
10
9
10
我们在 Windows Server 和 Hyper-V 方面没有太多经验,所以谁能解释一下这种现象?它是 Windows Server 问题吗?超V?这些平台上的 Java 错误?有解决办法吗?
编辑:一位同事编写了同一程序的 C# 版本:
private static Stopwatch stopwatch = new Stopwatch();
public static void Main()
{
stopwatch.Start();
Timer timer = new Timer(callback, null, TimeSpan.FromMilliseconds(10), TimeSpan.FromMilliseconds(10));
}
private static void callback(object state)
{
stopwatch.Stop();
TimeSpan span = stopwatch.Elapsed;
Console.WriteLine((int)span.TotalMilliseconds);
stopwatch.Restart();
}
这是两个应用程序在虚拟 Windows 服务器上并排工作的更新(部分)屏幕截图:
编辑: Java 程序的一些其他变体都产生(几乎)相同的输出:
- 一种变体,其中
System.nanoTime()被替换为System.currentTimeMillis() -
System.out.println()被定期打印的 StringBuilder 替换的变体 - 一种变体,其中调度机制被替换为单个线程,该线程通过
Thread.sleep()对自身进行计时 -
lastRunAt易变的变体
【问题讨论】:
-
我不知道为什么会发生这种情况,但我确实有一个建议,尝试使用一个小的 c# 应用程序来做同样的事情,看看结果是否相似。在windows server主机上运行这个app(希望也是windows 2012 R2),看看是不是也有时间问题,这是为了判断是windows server还是hyper-v的问题。
-
@Augusto 我已经用 C# 版本的程序更新了问题
-
@Malt 真的很奇怪!!!你能使用
virtual vm生成线程转储吗?可能正在分析转储将导致帮助.. -
罪魁祸首是
sysout?您可以尝试用appending to a StringBuilder替换打印语句,然后尝试打印相同的语句,以尽量减少外部因素的影响.. -
那些与程序不相等,
nanoTime()与 .net 调用不同,因此它可能从不同的来源获取信息。你试过System.currentTime()吗?