我有一个奇怪的问题 - 希望有人能向我解释发生了什么,并提供一种可能的解决方法。我正在Java中实现Z80核心,并尝试通过在单独的线程中使用java.util.Timer对象来减速。
基本设置是有一个线程每秒运行50次执行循环。在这个执行循环中,无论执行多少个周期,都会调用wait()。外部Timer线程将每20ms在Z80对象上调用notifyAll(),模拟PAL世嘉主系统时钟频率为3.54 MHz(左右)。
我上面描述的方法在Windows 7上完美运行(我尝试过两台机器),但我也尝试过两台Windows XP机器,在这两台机器上,Timer对象似乎会多睡觉约50%左右。这意味着一秒钟的仿真时间实际上需要大约1.5秒钟在Windows XP计算机上。
我已经尝试使用Thread.sleep()而不是Timer对象,但是效果完全相同。我知道大多数操作系统中的时间粒度都不超过1毫秒,但是我可以接受999毫秒或1001毫秒而不是1000毫秒。我不能忍受的是1562毫秒 - 我只是不明白我的方法为什么在较新版本的Windows上工作得好,而在旧版本上不行 - 我已经调查了中断周期等问题,但似乎没有找到解决方案。
请问有人能告诉我这个问题的原因和建议的解决方法吗?非常感谢。
更新:以下是我构建的一个小应用程序完整代码,以展示相同的问题:
所有主类所做的就是创建并启动其中一个工作线程。在Windows 7上,此代码产生约999ms-1000ms的时间,这完全没问题。然而,在Windows XP上运行相同的jar文件会产生约1562ms-1566ms的时间,我已经测试了两台不同的XP机器。它们都运行Java 6更新27。
我发现这个问题发生是因为计时器休眠了20ms(相当小的值)-如果我把所有执行循环放入等待wait() - notifyAll()周期中的一秒钟,这会产生正确的结果-我相信那些看到我试图做什么的人(模拟50fps的塞加主系统)将会看到这不是一个解决方案-它不会给出交互响应时间,跳过每50个中的49个。正如我所说,Win7可以很好地处理这个问题。如果我的代码太大,对不起 :-(
基本设置是有一个线程每秒运行50次执行循环。在这个执行循环中,无论执行多少个周期,都会调用wait()。外部Timer线程将每20ms在Z80对象上调用notifyAll(),模拟PAL世嘉主系统时钟频率为3.54 MHz(左右)。
我上面描述的方法在Windows 7上完美运行(我尝试过两台机器),但我也尝试过两台Windows XP机器,在这两台机器上,Timer对象似乎会多睡觉约50%左右。这意味着一秒钟的仿真时间实际上需要大约1.5秒钟在Windows XP计算机上。
我已经尝试使用Thread.sleep()而不是Timer对象,但是效果完全相同。我知道大多数操作系统中的时间粒度都不超过1毫秒,但是我可以接受999毫秒或1001毫秒而不是1000毫秒。我不能忍受的是1562毫秒 - 我只是不明白我的方法为什么在较新版本的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上,此代码产生约999ms-1000ms的时间,这完全没问题。然而,在Windows XP上运行相同的jar文件会产生约1562ms-1566ms的时间,我已经测试了两台不同的XP机器。它们都运行Java 6更新27。
我发现这个问题发生是因为计时器休眠了20ms(相当小的值)-如果我把所有执行循环放入等待wait() - notifyAll()周期中的一秒钟,这会产生正确的结果-我相信那些看到我试图做什么的人(模拟50fps的塞加主系统)将会看到这不是一个解决方案-它不会给出交互响应时间,跳过每50个中的49个。正如我所说,Win7可以很好地处理这个问题。如果我的代码太大,对不起 :-(