Java: Ungenauigkeit / Messfehler in System.currentTimeMillis() und new Date()

Zeitmessung in JavaUnglaublich, aber heute hat mich Java zum ersten Mal in meinem Leben enttäuscht:-(
Wie die Überschrift des Blogeintrags verrät, habe ich Ungenauigkeiten in der Zeitmessung von Java festgestellt. Normalerweise verwende ich Timestamps selten als Primery-Key in der Datenbank, aber wenn die eigentliche Verarbeitung unter 10 Millisekunden dauert, kann das zu Problemen unter Windows XP führen! Laut API bestimmt das darunter liegende Betriebssystem wie oft der Zeitwert aktualisiert wird. Mit anderen Worten: Windows XP (32 Bit) und Java Version: JDK 1.6.0_16 aktualisieren im Durchschnitt aller 15 ms die Systemzeit. Somit erhält man in meinem Beispiel(Datenbank-Primery-Key) zweimal den gleichen Timestamp und provoziert damit einen SQL-Fehler. Dabei spielt es keine Rolle, ob man die Funktion System.currentTimeMillis(); oder das Objekt new Date(); verwendet.

 

Das Test-Programm

package main;

import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.TimeZone;

public class Main {

	/**
	 * @param args
	 */
	public static void main(String[] args) {
		for (int i = 0; i < 25; i++) {
			Date myDate = new Date();
			System.out.println(format(myDate));
			System.out.println(System.currentTimeMillis());
			System.out.println("+++");				
		}
	}	
	
	public static String format(Date myDate){
		SimpleDateFormat dateFormat = new SimpleDateFormat("ss-SSS");
		dateFormat.setTimeZone(TimeZone.getTimeZone("GMT+1"));
		return dateFormat.format(myDate);
	}
}

 

Die Ausgabe

unter Windows XP (32 Bit)

52-235
1329146572250
+++
52-250
1329146572250
+++
52-250
1329146572250
+++
52-250
1329146572250
+++
52-250
1329146572250
+++
52-250
1329146572250
+++
52-250
1329146572250
+++
52-250
1329146572250
+++
52-250
1329146572250
+++
52-250
1329146572250
+++
52-250
1329146572250
+++
52-250
1329146572250
+++
52-250
1329146572250
+++
52-250
1329146572250
+++
52-250
1329146572250
+++
52-250
1329146572250
+++
52-250
1329146572250
+++
52-250
1329146572250
+++
52-250
1329146572250
+++
52-266
1329146572266
+++
52-266
1329146572266
+++
52-266
1329146572266
+++
52-266
1329146572266
+++
52-266
1329146572266
+++
52-266
1329146572266
+++

unter Windows 7 (64 Bit)

00-338
1329341760357
+++
00-358
1329341760358
+++
00-358
1329341760358
+++
00-358
1329341760358
+++
00-358
1329341760358
+++
00-358
1329341760358
+++
00-358
1329341760359
+++
00-359
1329341760359
+++
00-359
1329341760359
+++
00-359
1329341760359
+++
00-359
1329341760359
+++
00-359
1329341760359
+++
00-360
1329341760360
+++
00-360
1329341760360
+++
00-360
1329341760360
+++
00-360
1329341760360
+++
00-360
1329341760360
+++
00-360
1329341760361
+++
00-361
1329341760361
+++
00-361
1329341760361
+++
00-361
1329341760361
+++
00-361
1329341760361
+++
00-361
1329341760361
+++
00-362
1329341760362
+++
00-362
1329341760362
+++

 

Fazit

Der Test wurde mit derselben Hardware und der gleichen JDK Version (1.6.0_16) durchgeführt. Das Test-Programm zeigt einen deutlichen Unterschied zwischen Windows XP und Windows 7. Unter Windows XP wird in der Regel aller 15 ms die Systemzeit aktualisiert. Im Gegensatz dazu scheint Windows 7 wirklich jede Millisekunde die Systemzeit zu aktualisieren. Weitere Tests sind für Open Suse und Red Hat geplant.

 

Möglichkeiten der Zeitmessung in Java

Es gibt verschiedene Möglichkeiten die Zeit in Java zu messen. Zwei davon stelle ich hier vor:

 

Die Funktion System.currentTimeMillis()

Die Funktion System.currentTimeMillis() gibt die aktuelle Systemzeit in Millisekundenbereich zurück, jedoch hängt der tatsächliche Aktualisierungsrhythmus von dem eingesetzten Betriebssystem und dessen Konfiguration ab. Der zurückgegebene Wert bezieht sich auf die seit dem 01.01.1970 00:00 (UTC) vergangenen Millisekunden. Die genaue Definition der Funktion finden Sie in der Java API (http://docs.oracle.com/javase/7/docs/api/java/lang/System.html#currentTimeMillis%28%29). Somit eignet sich diese Funktion aufgrund ihrer möglichen Ungenauigkeiten nur bedingt für eine Performance-Messungen, jedoch kann man weiterhin eindeutige Timestamps mit dieser Funktion erzeugen, wenn die Bearbeitungszeit über 20 ms liegt.

 

Die Funktion System.nanoTime()

Mit der Java-Version 1.5 wurde die Funktion System.nanoTime() eingeführt. Diese Funktion wählt die genaueste verfügbare Zeitquelle aus und gibt deren Wert in Nanosekunden zurück. Der Bezugszeitpunkt der Zeitangabe oder die tatsächliche Genauigkeit bleiben jedoch unbekannt. Aus diesen Gründen können die Ausgaben der Funktion nur zur Berechnung von bereits verstrichener Zeit benutzt werden. Weitere Informationen finden Sie in der Java API (http://docs.oracle.com/javase/7/docs/api/java/lang/System.html#nanoTime%28%29). Die Funktion System.nanoTime() bietet derzeit die beste Möglichkeit um eine Performance-Messungen durchzuführen.

Quellen



4 Antworten : “Java: Ungenauigkeit / Messfehler in System.currentTimeMillis() und new Date()”

  1. Georg sagt:

    Diese Tatsache ist dokumentiert und die Nutzung eines Timestamp als primary key halte ich für grob fahrlässig…

  2. Doofe Frage, aber: Warum einen Timestamp als PK nehmen?

Kommentar verfassen