私には奇妙な問題があります-誰かが私に何が起こっているのか、そして可能な回避策を説明してくれることを望んでいます。別のスレッドでjava.util.Timerオブジェクトを使用して、JavaでZ80コアを実装し、速度を落とそうとしています。
基本的な設定では、1つのスレッドで1秒間に50回実行ループを実行しています。ただし、この実行ループ内では、多くのサイクルが実行されてから、wait()が呼び出されます。外部タイマースレッドは、20msごとにZ80オブジェクトでnotifyAll()を呼び出し、3.54 MHz(ish)のPALセガマスターシステムのクロック周波数をシミュレートします。
上記の方法は、Windows 7(2台のマシンを試した)で完全に機能しますが、2台のWindows XPマシンも試しましたが、両方で、Timerオブジェクトが約50%ほどオーバースリープしているようです。これは、Windows XPマシンでは、エミュレーション時間の1秒が実際には約1.5秒かかることを意味します。
Timerオブジェクトの代わりにThread.sleep()を使用してみましたが、これはまったく同じ効果があります。ほとんどのOSの時間の粒度は1ミリ秒よりも優れているとは思いませんが、1000ミリ秒ではなく999ミリ秒または1001ミリ秒に耐えることができます。私が我慢できないのは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();
}
}
}
メインクラスが行うのは、これらのワーカースレッドの1つを作成して開始することだけです。Windows 7では、このコードは約999ms〜1000msの時間を生成しますが、これはまったく問題ありません。ただし、同じjarをWindows XPで実行すると、約1562ms〜1566msの時間が発生します。これは、私がこれをテストした2台の別々のXPマシン上にあります。それらはすべてJava6update27を実行しています。
タイマーが20ms(非常に小さい値)スリープしているため、この問題が発生していることがわかります-1秒間すべての実行ループをwait wait()-notifyAll()サイクルにバングすると、正しい結果が生成されます-I '私がやろうとしていること(50fpsでセガマスターシステムをエミュレートする)を見る人は、これが解決策ではないことを理解するでしょう-それはインタラクティブな応答時間を与えず、50ごとに49をスキップします。私が言うように、Win7はこれにうまく対応します。私のコードが大きすぎる場合は申し訳ありません:-(