我有一个奇怪的问题 - 我希望有人可以向我解释发生了什么以及可能的解决方法。我正在用 Java 实现 Z80 内核,并试图通过在单独的线程中使用 java.util.Timer 对象来减慢它的速度。
基本设置是我有一个线程运行一个执行循环,每秒 50 次。在这个执行循环中,无论执行多少个循环,然后调用 wait()。外部 Timer 线程将每 20 毫秒调用一次 Z80 对象上的 notifyAll(),模拟 3.54 MHz(ish)的 PAL Sega Master System 时钟频率。
我上面描述的方法在 Windows 7 上完美运行(尝试了两台机器),但我也尝试了两台 Windows XP 机器,在这两台机器上,Timer 对象似乎睡过头了大约 50% 左右。这意味着在 Windows XP 机器上,一秒的仿真时间实际上需要大约 1.5 秒左右。
我曾尝试使用 Thread.sleep() 而不是 Timer 对象,但这具有完全相同的效果。我意识到大多数操作系统中的时间粒度并不优于 1 毫秒,但我可以忍受 999 毫秒或 1001 毫秒而不是 1000 毫秒。我无法忍受的是 1562 毫秒 - 我只是不明白为什么我的方法在较新版本的 Windows 上运行良好,但在较旧版本的 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();
}
}
}
主类所做的只是创建并启动这些工作线程之一。在 Windows 7 上,此代码产生大约 999 毫秒 - 1000 毫秒的时间,这完全没问题。然而,在 Windows XP 上运行相同的 jar 会产生大约 1562 毫秒 - 1566 毫秒的时间,这是在我测试过的两台单独的 XP 机器上。它们都在运行 Java 6 update 27。
我发现这个问题正在发生,因为定时器正在休眠 20 毫秒(相当小的值) - 如果我将所有执行循环一秒钟内放入等待等待() - notifyAll()循环,这会产生正确的结果 - 我'我确信看到我正在尝试做的事情(以 50fps 模拟 Sega Master 系统)的人会看到这不是一个解决方案 - 它不会给出交互式响应时间,每 50 个跳过 49 个。正如我所说, Win7 处理得很好。对不起,如果我的代码太大:-(