# Workaround für Thread.sleep()-Bug



## 0xdeadbeef (4. Jul 2008)

Ich poste das mal hier, weil ich denke, daß man kleine Werte für Thread.sleep() am ehesten bei Spielen benutzt...


Bekanntlich gibt es unter WinXP (u.ä.) einen Bug bei der Implementierung von Thread.sleep(), der dazu führt, daß man bei sehr kleinen Parameterwerten nicht nur unplausible Ergebnisse bekommt, sondern im schlimmsten Fall sogar die Systemzeit verstellen kann (weil die Systemuhr während er Programmausführung deutlich schneller läuft).
Das wurde vor langer Zeit mal diskutiert und ich habe damals als Workaround Sleep-Zeiten von unter 20ms verhindert, was auch ganz gut geklappt hat, aber auf schwachen Systemen halt eine CPU-Last von 100% verursachen kann.

Wie es der Zufall so will, bin ich heute zufällig über einen Workaround im Java Bugtracker gestolpert und wollte Euch nicht dumm sterben lassen, falls er hier noch nicht bekannt ist:

http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=6435126

Im Kern startet man einen Daemon-Thread, in dem man ein "Thread.sleep(Integer.MAX_VALUE)" aufruft.
Das führt anscheinend dazu, daß systemweit (!) auf eine Timerauflösung von 1ms (statt 10ms) umgestellt wird und man somit auch Sleep-Werte unter 10ms benutzen kann.
Weil die systemweite Timerauflösung sich nach der höchsten Anforderung der laufenden Prozesse richtet, kann es durchaus auch sein, daß bereits eine andere Anwendung die hohe Auflösung angefordert hat. Das erklärt vermutlich auch, warum die Sleep-Probleme nicht auf jedem Rechner aufgetreten sind (das mit dem Verstellen der Systemzeit hat aber vermutlich noch einen komplexeren Hintergrund).

Nebenbei: dem Bugtracker-Eintrag kann man auch entnehmen, daß es schon lange einen Schalter "ForceTimeHighResolution" für diesen Zweck gibt, der allerdings von Anfang an falsch implementiert war und man es für zu riskant hielt, die Funktionsweise des Schalters zu korrigieren, weil ja bislang alle damit zufrieden waren 

Leider kann ich den Workaround nicht wirklich testen, weil mein Rechner laut Perfmon bereits mit hoher Timerauflösung läuft. Falls jemand noch einen Rechner hat, auf dem das nicht der Fall ist (wie man es testet, ist ebenfalls im Bugtracker beschrieben), würde ich mich über eine Rückmeldung freuen, ob dieser Workaround tatsächlich funktioniert. Inbesondere würde ich natürlich auch gerne wissen, ob dieser Workaround das Verstellen der Systemzeit auf den dafür anfälligen Rechnern verhindert. Mein eigener (Firmen)-Testrechner ist leider nicht mehr existent.


----------



## SlaterB (4. Jul 2008)

was es nicht alles gibt..

bei mir jedenfalls keine Änderung,
bei

```
public class Test {

	public static void main(String[] args) throws Exception {
		trick17();
		Thread.sleep(500);
		long time = System.currentTimeMillis();
		for (int i = 0; i < 40; i++) {
			Thread.sleep(3);
			long newTime = System.currentTimeMillis();
			System.out.println("Time: " + (newTime - time));
			time = newTime;

		}
	}

	static void trick17() {
		new Thread() {
			{
				this.setDaemon(true);
				this.start();
			}

			public void run() {
				while (true) {
					try {
						Thread.sleep(Integer.MAX_VALUE);
					} catch (InterruptedException ex) {
						ex.printStackTrace();
					}
				}
			}
		};
	}

}
```
kommt mit oder ohne Trick 17 das typische
Time: 47
Time: 16
Time: 0
Time: 15
Time: 0
Time: 0
Time: 16
Time: 0
Time: 0
Time: 16
Time: 0
Time: 46
Time: 0
Time: 0
Time: 0
Time: 16
Time: 0
Time: 0
Time: 0
Time: 16
Time: 0
Time: 0
Time: 0
Time: 15
Time: 0
Time: 0
Time: 0
Time: 16
Time: 0
Time: 0
Time: 16
Time: 0
Time: 0
Time: 15
Time: 0
Time: 0
Time: 0
Time: 16
Time: 0
Time: 0
raus


----------



## Wildcard (4. Jul 2008)

Beim Testen kann ich leider nicht helfen, ich habe kein Windows System, aber... wow.
Sehr interessant fand ich das hier:


> at the start of the application create and start a daemon Thread that simply sleeps for a very long time (that isn't a multiple of 10ms) as this will set the timer period to be 1ms for the duration of that sleep


Warum wird die Auflösung nur dann erhöht, wenn der Prozess so lange schläft, das die Auflösung völlig egal ist (mal abgesehen von der seltsamen x*10 Einschränkung)? :lol:

Danke für diese Kuriosität  :lol:


----------



## 0xdeadbeef (4. Jul 2008)

@SlaterB: 
Ich fürchte, daß alleine die Aufrufe von "System.out.println" diese Messung unbrauchbar machen. Es wäre sinnvoller, eine Statistik zu machen und erst am Ende auszugeben.
Falls die Statistik genauso weit streut: hast Du mal mit Perfmon geschaut, ob Du eher 100+ oder 1000+ Interrupts pro Sekunde hast, während das Programm (nicht) läuft? Dazu müßte allerdings die Schleife etwas großzügiger dimensioniert sein.

@Wildcard: das "endlose" sleep muß man wohl nicht verstehen.


----------



## SlaterB (4. Jul 2008)

wie kann man da einen Einfuss von System.out.println vermuten,
was veranlasst dich dazu?
große Zeitsprünge wie die 46 in der Mitte könnte man ja damit zu erschlagen versuchen,
aber wenn so regelmäßig "0,0, typischer Zeitsprung von ~16" kommt,
dann ist das doch ein glasklares Spiel


hier nochmal mit StringBuilder und mehr sleep()

```
StringBuilder b = new StringBuilder();
					long time = System.currentTimeMillis();
					for (int i = 0; i < 40; i++) {
						Thread.sleep(40);
						long newTime = System.currentTimeMillis();
						b.append("\nTime: ");
						b.append(newTime - time);
						time = newTime;

					}
					System.out.println(b);
```

Time: 46
Time: 32
Time: 47
Time: 31
Time: 47
Time: 47
Time: 31
Time: 47
Time: 31
Time: 47
Time: 31
Time: 47
Time: 47
Time: 31
Time: 47
Time: 31
Time: 47
Time: 31
Time: 47
Time: 31
Time: 47
Time: 47
Time: 31
Time: 47
Time: 32
Time: 46
Time: 32
Time: 47
Time: 46
Time: 32
Time: 47
Time: 31
Time: 47
Time: 31
Time: 47
Time: 31
Time: 47
Time: 47
Time: 31
Time: 47

wieder ganz deutlich das gleiche System,

das beweist natürlich nur, dass bei mir nix passiert ist,
sonst steckt da keine Aussage dahinter 

zu Perfmon kann ich nix sagen, egal was das anzeigen würde, wäre mir egal/ hätte keine Aussage für mich,
solange ein eigener Test nicht geht, ist currentTimeMillis() so ungenau wie bekannt


----------



## Wildcard (4. Jul 2008)

Es ist tatsächlich so, dass System outs Messungen total verändern können. Wenn ich sowas mache, dann alle Ausgaben in Variablen belassen und am Ende ausgeben. So ganz genau konnte ich mir schon damals nicht erklären was da passiert  ???:L


----------



## 0xdeadbeef (4. Jul 2008)

Habe mal selber einen kleinen Test geschrieben - nicht für mich, sondern für bereitwillige Tester, bei denen der Systemtimer ohne diesen Workaround mit 10ms läuft. Bei mir macht das Ein- und Auskommentieren erwartungsgemäß keinen Unterschied, weil der Systemtimer so oder so mit 1ms läuft.

Meine Werte sind:

```
Min:  0
Max:  16
Mean: 3
```

Daß die Werte bei so kleinen Sleep-Perioden jittern, ist absolut zu erwarten! Bloß durch den 1ms-Systemtimer wird Windows ja noch nicht zu einem Echtzeitsystem.

Wie gesagt: wichtig ist, vorher mit "perfmon" (einfach in der Kommandozeile eingeben) zu prüfen, ob man ohne "Trick17" deutlich unter 1000 Interrupts hat und mit "Trick17" mehr als 1000. Dazu in das Meßfenster rechts klicken, dann "Leistungsindikatoren hinzufügen", dann Datenobjekt = Prozessor, Leistungsindikator = Interrupts/s-.
Bei mir sind es ca. 1300 Interrupt/s -> ich habe einen 1ms-Timer.

Hier der Test.


```
public class TimerTest {

	public static void main(String[] args) throws Exception {
		trick17();
		Thread.sleep(500);
		int minTime = Integer.MAX_VALUE;
		int maxTime = 0;
		int ctrTime = 0;
		int meanTime = 0;
		long sumTime = 0;
		for (int i = 0; i < 4000; i++) {
			long timeStamp = System.currentTimeMillis();
			Thread.sleep(3);
			int curTime = (int)(System.currentTimeMillis() - timeStamp);
			ctrTime++;
			sumTime += curTime;
			meanTime = (int)(sumTime/ctrTime);
			if (curTime > maxTime)
				maxTime = curTime;
			if (curTime < minTime)
				minTime = curTime;

		}
		System.out.println("Min:  " + minTime);
		System.out.println("Max:  " + maxTime);
		System.out.println("Mean: " + meanTime);
	}

	static void trick17() {
		new Thread() {
			{
				this.setDaemon(true);
				this.start();
			}

			public void run() {
				while (true) {
					try {
						Thread.sleep(Integer.MAX_VALUE);
					} catch (InterruptedException ex) {
						ex.printStackTrace();
					}
				}
			}
		};
	}

}
```


----------



## SlaterB (4. Jul 2008)

?
ich bekomme genau die gleichen Ergebnisse, also vor allem mean = 3,
max in drei Durchläufen 78, 31, 16, solche Aussetzer kann man in nebenläufigen Betriebssystemen ja wohl kaum verhindern,

dass der Durchschnitt 3 sein wird sieht man ja auch schon an meinem Log aus dem zweiten Posting,
aber was bringt das? trotzdem ist die Uhr doch ungenau, wenn sie 4x um 0 ms springt und dann 1x um 16,
denn das lassen deine Werte mit Min = 0 und Max = 16 auch stark vermuten,

probier doch mal bitte meinen Test aus mit Ausgabe der Unterschiede pro Schleifendurchgang, gerne auch mit StringBuilder,
auch Wildcard vielleicht?

wenn sich das gleiche Bild mit dem 16-Sprüngen ergibt, worüber diskutieren wir dann eigentlich hier?,
nicht über die Java-Ms-Zeit sondern über die Systemzeit in allen anderen Programmiersprachen?


----------



## 0xdeadbeef (4. Jul 2008)

Mir geht es ja gar nicht so sehr um die Genauigkeit. Wie gesagt ist es bei einem "normalen" Betriebssystem wie XP kaum zu erwarten, daß Timings auf wenige Millisekunden genau eingehalten werden.
Ich versuche in erster Linie herauszufinden, ob die KATASTROPHALEN Nebenwirkungen von Sleep-Perioden kleiner 10ms durch diesen Workaround ausbleiben. Wie gesagt: ich hatte mal in der Firma einen PC, bei dem die Systemuhr schneller lief, wenn man in einem Java-Programm Sleep-Werte unter 10ms benutzt hat. Leider habe ich den aber nicht mehr, also hätte ich in erster Linie gern einen Tester dafür.

Zweitens würde ich gerne wissen, ob man mit diesem Workaround tatsächlich das Aufrufraster systemweit verstellen kann. Auch das kann ich mit meinem PC nicht testen, weil er bereits ohne den Workaround ein 1ms-Raster verwendet.

Nebenbei: daß der Mittelwert genau stimmt, kann kein Zufall sein, ist aber irgendwie auch irritierend. Bei einer einfachen Implementierung wäre zu erwarten, daß die angeforderte Sleep-Zeit im Mittel immer überschritten wird.
Daß das nicht der Fall ist, kann nur bedeuten, daß sich die Virtual Machine oder Windows zumindest die letzte Sleep-Anforderung merkt, die tatsächlich verstrichene Zeit ausmißt und beim nächsten Aufruf kompensiert. Eigentlich muß aber eine Statistik über mehrere Werte geführt werden, weil ja auch die Kompensation falsch sein könnte.


----------



## SlaterB (4. Jul 2008)

du teilst ja am Ende durch die Anzahl der Versuche, bis zur 4 müsste also durchschnittlich bei jedem Versuch 16% Fehler sein,

aber stimmt schon, irgendwie wird ja doch um die 3 ms gemessen wenn genau 5-6 Runden langfristig in einem 16ms-Sprung passen,
werde das gleich mal zusätzlich mit nanoTime() messen

------

und weils dich so brennend interessiert habe ich dann doch perfmon angeschmissen,
schon beim Start von Eclipse gehts von 100 auf bis zu 400 hoch,
beim TimerTest-Programm dann etwas über 1000, ja

bei 
Thread.sleep(1000000);
übrigens auch, soviel zur 10er-Teilbarkeit


----------



## 0xdeadbeef (4. Jul 2008)

Hm, alles recht kurios 

Habe meinen Testcode nochmal erweitert, um die Häufungen zu beobachten:


```
public class TimerTest {
	final static int MAX = 20;
	
	public static void main(String[] args) throws Exception {		
		trick17();
		Thread.sleep(500);
		int statistics[] = new int[MAX+1];
		int minTime = Integer.MAX_VALUE;
		int maxTime = 0;
		int ctrTime = 0;
		int meanTime = 0;
		long sumTime = 0;
		
		for (int i=0; i<MAX+1; i++)
			statistics[i] = 0;
		
		for (int i = 0; i < 4000; i++) {
			long timeStamp = System.currentTimeMillis();
			Thread.sleep(3);
			int curTime = (int)(System.currentTimeMillis() - timeStamp);
			if (curTime < MAX)
				statistics[curTime]++;
			else
				statistics[MAX]++;
			ctrTime++;
			sumTime += curTime;
			meanTime = (int)(sumTime/ctrTime);
			if (curTime > maxTime)
				maxTime = curTime;
			if (curTime < minTime)
				minTime = curTime;

		}
		System.out.println("Min:  " + minTime);
		System.out.println("Max:  " + maxTime);
		System.out.println("Mean: " + meanTime+"\n");
		for (int i=0; i<MAX+1; i++)
			System.out.println(i+" ms: " + statistics[i]);
		System.out.println(">"+MAX+" ms: " + statistics[MAX]);
	}

	static void trick17() {
		new Thread() {
			{
				this.setDaemon(true);
				this.start();
			}

			public void run() {
				while (true) {
					try {
						Thread.sleep(Integer.MAX_VALUE);
					} catch (InterruptedException ex) {
						ex.printStackTrace();
					}
				}
			}
		};
	}

}
```

Für 3ms ausgeführt:

```
Min:  0
Max:  16
Mean: 3

0 ms: 2999
1 ms: 0
2 ms: 0
3 ms: 0
4 ms: 0
5 ms: 0
6 ms: 0
7 ms: 0
8 ms: 0
9 ms: 0
10 ms: 0
11 ms: 0
12 ms: 0
13 ms: 0
14 ms: 0
15 ms: 375
16 ms: 626
17 ms: 0
18 ms: 0
19 ms: 0
20 ms: 0
>20 ms: 0
```

Und für 10ms (MAX = 30)

```
Min:  0
Max:  16
Mean: 10

0 ms: 1248
1 ms: 0
2 ms: 0
3 ms: 0
4 ms: 0
5 ms: 0
6 ms: 0
7 ms: 0
8 ms: 0
9 ms: 0
10 ms: 0
11 ms: 0
12 ms: 0
13 ms: 0
14 ms: 0
15 ms: 1031
16 ms: 1721
17 ms: 0
18 ms: 0
19 ms: 0
20 ms: 0
21 ms: 0
22 ms: 0
23 ms: 0
24 ms: 0
25 ms: 0
26 ms: 0
27 ms: 0
28 ms: 0
29 ms: 0
30 ms: 0
>30 ms: 0
```

Wie schon die anderen Tests andeuten, werden überhaupt nur Wartezeiten von 0, 15 und 16 benutzt, um die drei Millisekunden zu approximieren. Bei 10ms ist das Bild praktisch identisch: auch hier werden die 10ms aus den gleichen drei Werten konstruiert.

@SlaterB: es verändert sich zwar der Wert in Perfmon, aber an der Aufrufstatistik ändert sich bei Dir nichts???
Kannst Du es eventuell mal mit/ohne Trick17 ohne Eclipse versuchen? Und hast Du mal darauf geachtet, ob während des Tests mit Trick17 die Systemzeit schneller läuft?


----------



## SlaterB (4. Jul 2008)

mit NanoTime:

```
StringBuilder b = new StringBuilder();
					long time = System.currentTimeMillis();
					long nanoTime = System.nanoTime();
					for (int i = 0; i < 40; i++) {
						nanoTime = System.nanoTime();
						Thread.sleep(7);
						long newNanoTime = System.nanoTime();
						long newTime = System.currentTimeMillis();
						b.append("\nTime: ");
						long timeDif = newTime - time;
						if (timeDif < 10) {
							b.append(" ");
						}
						b.append(timeDif);
						b.append("  ");
						b.append(newNanoTime - nanoTime);
						time = newTime;

					}
					System.out.println(b);

Ausgabe:

Time: 16  7685614
Time:  0  7685334
Time: 16  7792611
Time:  0  7799874
Time: 15  7836750
Time:  0  7770541
Time: 16  7790376
Time:  0  7798756
Time: 15  7799315
Time:  0  7801271
Time: 16  7800153
Time:  0  7797639
Time: 16  7802389
Time:  0  7800712
Time: 15  7806858
Time:  0  7789258
Time: 16  7786185
Time:  0  7797639
Time: 16  7809093
Time:  0  7793728
Time: 15  7797640
Time:  0  7801830
Time: 16  7801830
Time:  0  7804344
Time: 15  7798477
Time:  0  7795963
Time: 16  7851557
Time:  0  7754897
Time: 16  7791493
Time:  0  7806858
Time: 15  7796242
Time:  0  7802109
Time: 16  7789259
Time:  0  7802109
Time: 16  7790934
Time:  0  7801830
Time: 15  7799595
Time:  0  7802388
Time: 16  7817754
Time:  0  7864966
```

wenn ich trick17() ausschalte, dann habe ich diesmal sogar eine Abweichung,
konstant gibt es zum Anfang des Programms einen Huckel:

```
Time: 15  15471799
Time: 16  229079
Time:  0  7762439
Time: 15  7785906
Time:  0  7787861
```
dürfte hauptsächlich am Programmstart liegen, aber auch bei einer Schleife um diese 40er-Messung gibts ohne trick17()  ab und zu Probleme bei der ersten Messung,

mit und ohne trick17() kommts im weiteren Verlauf durchaus auch mal zu Wert bis zu 15ms, so genau wie in der Ausgabe ist das also nicht immer,
als nächstes muss ich dann wohl ne Statistik bauen,

interessant übrigens, dass 7 ms nun gar nicht 7000000 Nanosekunden sind,
gibts da einen Umrechnungsfaktor oder konstanten Aufschlag?

--------

> @SlaterB: es verändert sich zwar der Wert in Perfmon, aber an der Aufrufstatistik ändert sich bei Dir nichts???
> Kannst Du es eventuell mal mit/ohne Trick17 ohne Eclipse  versuchen?

bei ms erwarte ich nicht mehr viel, zu NanoSekunden werde ich nun aber auch wie du eine Wertetabelle führen,
gerne dann auch mal ohne Eclipse

die 400 bei perfmon meinte ich nur zum Start von Eclipse, danach wieder 100 und 1000 beim Programm


----------



## 0xdeadbeef (4. Jul 2008)

Öh, Moment?
Willst Du mir sagen, daß currentTimeMillis das Problem ist? Da bin jetzt aber schon etwas baff.
Muß ich gerade mal selber testen. Leider gibt es nanoTime ja erst ab 1.5, oder? Wollte eigentlich 1.4-kompatibel bleiben...

So, hier das Update:


```
public class TimerTest {
	final static int MAX = 20;
	
	public static void main(String[] args) throws Exception {		
		trick17();
		Thread.sleep(500);
		
		int statistics[] = new int[MAX+1];
		int minTime = Integer.MAX_VALUE;
		int maxTime = 0;
		int ctrTime = 0;
		int meanTime = 0;
		long sumTime = 0;

		int statisticsMicro[] = new int[MAX+1];
		int minTimeMicro = Integer.MAX_VALUE;
		int maxTimeMicro = 0;
		int ctrTimeMicro = 0;
		int meanTimeMicro = 0;
		long sumTimeMicro = 0;		
		
		for (int i=0; i<MAX+1; i++) {
			statistics[i] = 0;
			statisticsMicro[i] = 0;
		}
		
		for (int i = 0; i < 4000; i++) {
			long timeStamp = System.currentTimeMillis();
			long timeStampNano = System.nanoTime();
			Thread.sleep(3);
			int curTimeMicro = (int)(System.nanoTime() - timeStampNano)/1000;
			int curTime = (int)(System.currentTimeMillis() - timeStamp);
			//ms
			if (curTime < MAX)
				statistics[curTime]++;
			else
				statistics[MAX]++;
			ctrTime++;
			sumTime += curTime;
			meanTime = (int)(sumTime/ctrTime);
			if (curTime > maxTime)
				maxTime = curTime;
			if (curTime < minTime)
				minTime = curTime;
			//us
			if (curTimeMicro < MAX*1000)
				statisticsMicro[curTimeMicro/1000]++;
			else
				statisticsMicro[MAX]++;
			ctrTimeMicro++;
			sumTimeMicro += curTimeMicro;
			meanTimeMicro = (int)(sumTimeMicro/ctrTimeMicro);
			if (curTimeMicro > maxTimeMicro)
				maxTimeMicro = curTimeMicro;
			if (curTimeMicro < minTimeMicro)
				minTimeMicro = curTimeMicro;

		}
		System.out.println("Min:  " + minTime  + "ms (" + minTimeMicro+" us)");
		System.out.println("Max:  " + maxTime  + "ms (" + maxTimeMicro+" us)");
		System.out.println("Mean: " + meanTime + "ms (" + meanTimeMicro+" us)"+"\n");
		for (int i=0; i<MAX+1; i++)
			System.out.println(i+" ms: " + statistics[i] + " ("+statisticsMicro[i]+")");
		System.out.println(">"+MAX+" ms: " + statistics[MAX] + " ("+statisticsMicro[MAX]+")");
	}

	static void trick17() {
		new Thread() {
			{
				this.setDaemon(true);
				this.start();
			}

			public void run() {
				while (true) {
					try {
						Thread.sleep(Integer.MAX_VALUE);
					} catch (InterruptedException ex) {
						ex.printStackTrace();
					}
				}
			}
		};
	}

}
```

Und das Ergebnis:


```
Min:  0ms (2996 us)
Max:  16ms (7285 us)
Mean: 3ms (3906 us)

0 ms: 2999 (0)
1 ms: 0 (0)
2 ms: 0 (1)
3 ms: 0 (3859)
4 ms: 0 (128)
5 ms: 0 (8)
6 ms: 0 (3)
7 ms: 0 (1)
8 ms: 0 (0)
9 ms: 0 (0)
10 ms: 0 (0)
11 ms: 0 (0)
12 ms: 0 (0)
13 ms: 0 (0)
14 ms: 0 (0)
15 ms: 375 (0)
16 ms: 626 (0)
17 ms: 0 (0)
18 ms: 0 (0)
19 ms: 0 (0)
20 ms: 0 (0)
>20 ms: 0 (0)
```

Wie man sieht, liefert tatsächlich currentTimeMillis() Bullshit zurück, denn in Wirklichkeit werden die 3ms viel exakter eingehalten. Der Maximalwert ist in Wirklichkeit um die 7ms, die komischen Häufungen bei 0, 15 und 16ms existieren überhaupt nicht. Unter diesen Rahmenbedingungen kann man Messungen mit currentTimeMillis() ja wirklich vollständig vergessen.


----------



## SlaterB (4. Jul 2008)

tja, es ist wie es ist

hier nochmal arg zusammengeschustert ein Verteilungstest

```
public class TimerTest {
	final static int MAX = 20;

	public static void main(String[] args) throws Exception {
		trick17();
		Thread.sleep(500);
		int statistics[] = new int[MAX + 1];
		int minTime = Integer.MAX_VALUE;
		int maxTime = 0;
		int ctrTime = 0;
		int meanTime = 0;
		long sumTime = 0;

		long dif = 0;
		int mean = 3892000;
		for (int i = 0; i < MAX + 1; i++)
			statistics[i] = 0;

		for (int i = 0; i < 1000; i++) {
			long timeStamp = System.nanoTime();
			Thread.sleep(3);
			int curTime = (int) (System.nanoTime() - timeStamp);
			curTime -= mean;
			dif += Math.abs(curTime);
			curTime /= 1000;
			// if (i < 20) {
			// System.out.println(curTime);
			// }

			if (curTime < 0) {
				statistics[0]++;
			} else if (curTime < MAX) {
				statistics[curTime]++;
			} else {
				statistics[MAX]++;
			}
			ctrTime++;
			sumTime += curTime;
			meanTime = (int) (sumTime / ctrTime);
			if (curTime > maxTime)
				maxTime = curTime;
			if (curTime < minTime)
				minTime = curTime;

		}
		System.out.println("Min:  " + minTime);
		System.out.println("Max:  " + maxTime);
		System.out.println("Mean: " + meanTime);
		System.out.println("Dif: " + dif + "\n");
		for (int i = 0; i <= MAX; i++) {
			System.out.println((i + 100) + " ms: " + statistics[i]);
		}
	}

	static void trick17() {
		new Thread() {
			{
				this.setDaemon(true);
				this.start();
			}

			public void run() {
				while (true) {
					try {
						Thread.sleep(Integer.MAX_VALUE);
					} catch (InterruptedException ex) {
						ex.printStackTrace();
					}
				}
			}
		};
	}
}
```
hab leider grad keine Lust, alles richtig zu benennen und zu kommentieren 

grob gesagt ergibt sich eine nanoTime() von rund 3.900.000 pro Durchlauf,
davon ziehe ich nun einen vorher gemachten Erfahungswert ab so dass nur die interessanten hinteren variablen Zahlen bleiben,
noch geteilt usw, damits ins Array passt und gibt bei mir ne Verteilung von


```
Min:  -603
Max:  2360
Mean: 12
Dif: 23997897

100 ms: 93
101 ms: 8
102 ms: 12
103 ms: 4
104 ms: 21
105 ms: 22
106 ms: 17
107 ms: 40
108 ms: 34
109 ms: 79
110 ms: 107
111 ms: 178
112 ms: 136
113 ms: 61
114 ms: 40
115 ms: 17
116 ms: 15
117 ms: 13
118 ms: 8
119 ms: 6
120 ms: 89
```
die Werte sind relativ aussagelos, wichtig ist nur der Vergleich zu ohne trick17(),
und da gibts bei mir keinen nennenswerten Unterschied, bis auf den Huckel am Anfang, der regelmäßig zu einem hohen Anfangswert und damit 
Max:  > 10000
führt, das erhöht auch den Mean und Dif, 
im Grunde bleibt die Verteilung aber gleich,
egal ob in Eclipse oder ohne,

Fazit für mich: NanoTime bei beiden sehr genau, 
MilliTime bei beiden und anscheinend auch auf deinem PC ungenau wie man es kennt,

ob die 1000 statt 100 in perfmon irgendwo sonst irgendeine Auswirkung haben kann ich nicht sagen


----------



## SlaterB (4. Jul 2008)

> Und hast Du mal darauf geachtet, ob während des Tests mit Trick17 die Systemzeit schneller läuft?

ach je, die Frage habe ich bewußt die ganze Zeit ausgeklammert,
das ist ja nicht zu messen, dazu will ich kein (aktuelles TestProgramm-)Statement abgeben

über Monate und Jahre gesehen ist meine PC-Uhr locker 1 Min. pro Monat zu schnell, möchte ich vermuten,
aber belegen oder beursachen kann ich das nicht, verwende auch nicht so viel Thread.sleep()


----------



## 0xdeadbeef (4. Jul 2008)

Wir reden hier nicht von solchen Kleinigkeiten. Bei meinem ehemaligen Test-PC war eine Minute in ein paar Sekunden rum. Da konnte man die analoge Windows-Uhr im Kreis flitzen sehen. Nach einem kurzen (!) Test war die Systemzeit um mehrere Minuten daneben.


----------

