我有一個奇怪的問題 - 我希望有人能向我解釋發生了什麼事以及可能的解決方法。我在Java中實現了一個Z80內核,並試圖通過在單獨的線程中使用java.util.Timer對象來減慢速度。Windows XP與Windows 7的Java計時準確性
基本設置是我有一個線程運行一個執行循環,每秒50次。在這個執行循環中,執行多個循環,然後調用wait()。外部定時器線程將每20ms調用Z80對象的notifyAll(),模擬3.54 MHz(ish)的PAL Sega主系統時鐘頻率。
我上面描述的方法在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();
}
}
}
所有主類所做的就是創建和啓動這些工作線程之一。在Windows 7上,此代碼產生大約999ms到1000ms的時間,這非常好。然而,在Windows XP上運行相同的jar會產生大約1562ms到1566ms的時間,這是在我測試過的兩臺獨立的XP機器上。他們都運行Java 6更新27
我覺得這個問題正在發生,因爲定時器沉睡了20毫秒(相當小的值) - 如果我塞子所有單個第二的執行環插入等待觀望() - notifyAll()循環,這會產生正確的結果 - 我敢肯定,看到我想要做什麼的人(以50fps模擬世嘉主系統)會看到這不是一個解決方案 - 但它不會給出交互式響應時間,每50次跳過49次。正如我所說,Win7可以很好地處理這個問題。很抱歉,如果我的代碼太大:-(
有趣的問題。您是否可以提供展示此行爲的獨立代碼片段? – NPE
如果你喜歡,我可以給你定時器的源代碼嗎?我會給你很多東西,但是Z80內核變得相當龐大;-) – PhilPotter1987
@aix *「獨立代碼片段」*自包含代碼可能很短,但它不能(根據定義)是[片段](http://en.wikipedia.org/wiki/Snippet_%28programming%29)。我建議發佈[SSCCE](http://pscode.org/sscce.html)。 –