Windows XP与Windows 7上的Java计时准确性

Phi*_*987 9 java multithreading z80 timing

我有一个奇怪的问题 - 我希望有人可以向我解释发生了什么,以及可能的解决方法.我在Java中实现了一个Z80核心,并试图通过在一个单独的线程中使用java.util.Timer对象来减慢它的速度.

基本设置是我有一个线程运行一个执行循环,每秒50次.在此执行循环中,执行许多循环,然后调用wait().外部Timer线程将每隔20ms调用Z80对象上的notifyAll(),模拟PAL Sega主系统时钟频率为3.54 MHz(ish).

我上面描述的方法在Windows 7(试过两台机器)上工作得很好,但我也试过两台Windows XP机器,而且在这两台机器上,Timer对象似乎睡过了大约50%左右.这意味着在Windows XP计算机上,一秒钟的仿真时间实际上大约需要1.5秒左右.

我尝试使用Thread.sleep()而不是Timer对象,但这具有完全相同的效果.我意识到大多数操作系统的时间粒度不会超过1毫秒,但我可以忍受999毫秒或1001毫秒而不是1000毫秒.我不能忍受的是1562ms - 我只是不明白为什么我的方法在较新版本的Windows上运行正常,但不是旧版本 - 我调查了中断期等等,但似乎没有已经开发出一种解决方法.

有谁能告诉我这个问题的原因和建议的解决方法?非常感谢.

更新:这是我为了显示相同问题而构建的较小应用的完整代码:

import java.util.Timer;
import java.util.TimerTask;

public class WorkThread extends Thread
{
   private Timer timerThread;
   private WakeUpTask timerTask;

   public WorkThread()
   {
      timerThread = new Timer();
      timerTask = new WakeUpTask(this);
   }

   public void run()
   {
      timerThread.schedule(timerTask, 0, 20);
      while (true)
      {
         long startTime = System.nanoTime();
         for (int i = 0; i < 50; i++)
         {
            int a = 1 + 1;
            goToSleep();
         }
         long timeTaken = (System.nanoTime() - startTime) / 1000000;
         System.out.println("Time taken this loop: " + timeTaken + " milliseconds");
      }
   }

   synchronized public void goToSleep()
   {
      try
      {
         wait();
      }
      catch (InterruptedException e)
      {
         System.exit(0);
      }
   }

   synchronized public void wakeUp()
   {
      notifyAll();
   }

   private class WakeUpTask extends TimerTask
   {
       private WorkThread w;

       public WakeUpTask(WorkThread t)
       {
          w = t;
       }

       public void run()
       {
          w.wakeUp();
       }
   }
}
Run Code Online (Sandbox Code Playgroud)

所有主类都创建并启动其中一个工作线程.在Windows 7上,此代码产生的时间约为999毫秒 - 1000毫秒,这完全没问题.然而,在Windows XP上运行相同的jar会产生大约1562ms到1566ms的时间,这是在我测试过的两台独立的XP机器上.它们都运行Java 6更新27.

我发现这个问题正在发生,因为Timer正在休眠20ms(相当小的值) - 如果我将所有执行循环一秒钟塞进等待wait() - notifyAll()循环,这会产生正确的结果 - 我确定那些看到我正在尝试做的事情(以50fps模拟Sega Master System)的人会看到这不是一个解决方案 - 它不会给出交互式响应时间,每50个跳过49个.正如我所说,Win7应对此问题.对不起,如果我的代码太大:-(

Tim*_*der 5

有谁能告诉我这个问题的原因和建议的解决方法?

您看到的问题可能与时钟分辨率有关.某些操作系统(Windows XP和更早版本)因睡眠过度而臭名昭着,并且在等待/通知/睡眠(一般中断)时速度慢.与此同时,其他操作系统(我见过的每一台Linux)都非常出色地在指定的时刻返回控制.

解决方法?如果持续时间较短,请使用实时等待(忙循环).持续时间较长,睡眠的时间比实际需要的时间短,然后等待剩下的时间.