Das Javadoc für SimpleDateFormat gibt an, dass SimpleDateFormat nicht synchronisiert ist.
"Datumsformate werden nicht synchronisiert. Es wird empfohlen, separate Formatinstanzen für jeden Thread zu erstellen. Wenn mehrere Threads gleichzeitig auf ein Format zugreifen, muss es extern synchronisiert werden."
Was ist jedoch der beste Ansatz für die Verwendung einer Instanz von SimpleDateFormat in einer Umgebung mit mehreren Threads? Hier sind einige Optionen, an die ich gedacht habe: Ich habe in der Vergangenheit die Optionen 1 und 2 verwendet, bin aber gespannt, ob es bessere Alternativen gibt oder welche dieser Optionen die beste Leistung und Parallelität bieten.
Option 1: Erstellen Sie bei Bedarf lokale Instanzen
public String formatDate(Date d) {
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
return sdf.format(d);
}
Option 2: Erstellen Sie eine Instanz von SimpleDateFormat als Klassenvariable, synchronisieren Sie jedoch den Zugriff darauf.
private SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
public String formatDate(Date d) {
synchronized(sdf) {
return sdf.format(d);
}
}
Option 3: Erstellen Sie ein ThreadLocal, um für jeden Thread eine andere Instanz von SimpleDateFormat zu speichern.
private ThreadLocal<SimpleDateFormat> tl = new ThreadLocal<SimpleDateFormat>();
public String formatDate(Date d) {
SimpleDateFormat sdf = tl.get();
if(sdf == null) {
sdf = new SimpleDateFormat("yyyy-MM-hh");
tl.set(sdf);
}
return sdf.format(d);
}
Antworten:
Das Erstellen von SimpleDateFormat ist teuer . Verwenden Sie dies nur, wenn es selten gemacht wird.
OK, wenn Sie mit ein bisschen Blockierung leben können. Verwenden Sie diese Option, wenn formatDate () nicht häufig verwendet wird.
Schnellste Option, wenn Sie Threads wiederverwenden ( Thread-Pool ). Verwendet mehr Speicher als 2. und hat einen höheren Startaufwand.
Für Anwendungen sind sowohl 2. als auch 3. praktikable Optionen. Welches für Ihren Fall am besten geeignet ist, hängt von Ihrem Anwendungsfall ab. Vorsicht vor vorzeitiger Optimierung. Tun Sie es nur, wenn Sie glauben, dass dies ein Problem ist.
Für Bibliotheken, die von Drittanbietern verwendet werden, würde ich Option 3 verwenden.
quelle
SimpleDateFormat
als Instanzvariable deklarieren, können wirsynchronized block
sie threadsicher machen. Aber Sonar zeigt Warnung Tintenfisch-AS2885 . Gibt es eine Möglichkeit, das Sonarproblem zu lösen?Die andere Option ist Commons Lang FastDateFormat , Sie können sie jedoch nur zur Datumsformatierung und nicht zum Parsen verwenden.
Im Gegensatz zu Joda kann es als Ersatz für die Formatierung dienen. (Update: Seit Version 3.3.2 kann FastDateFormat einen FastDateParser erstellen , der einen thread-sicheren Ersatz für SimpleDateFormat darstellt.)
quelle
FastDateFormat
hat auchparse()
MethodeWenn Sie Java 8 verwenden, möchten Sie möglicherweise verwenden
java.time.format.DateTimeFormatter
:z.B:
quelle
Commons Lang 3.x verfügt jetzt sowohl über FastDateParser als auch über FastDateFormat. Es ist threadsicher und schneller als SimpleDateFormat. Es werden auch dieselben Format- / Analysemusterspezifikationen wie bei SimpleDateFormat verwendet.
quelle
Verwenden Sie nicht SimpleDateFormat, sondern stattdessen DateTimeFormatter von joda-time. Auf der Parsing-Seite ist es etwas strenger und daher kein Ersatz für SimpleDateFormat, aber die Joda-Zeit ist in Bezug auf Sicherheit und Leistung viel freundlicher.
quelle
Ich würde sagen, erstellen Sie eine einfache Wrapper-Klasse für SimpleDateFormat, die den Zugriff auf parse () und format () synchronisiert und als Drop-In-Ersatz verwendet werden kann. Narrensicherer als Ihre Option Nr. 2, weniger umständlich als Ihre Option Nr. 3.
Es scheint, als wäre es eine schlechte Entwurfsentscheidung der Java-API-Designer gewesen, SimpleDateFormat nicht synchronisiert zu machen. Ich bezweifle, dass jemand erwartet, dass format () und parse () synchronisiert werden müssen.
quelle
Eine weitere Option besteht darin, Instanzen in einer thread-sicheren Warteschlange zu halten:
Die Größe von dateFormatQueue sollte ungefähr der geschätzten Anzahl von Threads entsprechen, die diese Funktion routinemäßig gleichzeitig aufrufen können. Im schlimmsten Fall, wenn mehr Threads als diese Nummer tatsächlich alle Instanzen gleichzeitig verwenden, werden einige SimpleDateFormat-Instanzen erstellt, die nicht an dateFormatQueue zurückgegeben werden können, da sie voll sind. Dies erzeugt keinen Fehler, sondern verursacht nur die Strafe für das Erstellen von SimpleDateFormat, die nur einmal verwendet werden.
quelle
Ich habe dies gerade mit Option 3 implementiert, aber einige Codeänderungen vorgenommen:
Möglicherweise möchten Sie das Gebietsschema und die Zeitzone festlegen, es sei denn, Sie möchten wirklich die Standardeinstellungen festlegen (Standardeinstellungen sind bei Java sehr fehleranfällig).
quelle
Stellen Sie sich vor, Ihre Anwendung hat einen Thread. Warum sollten Sie dann den Zugriff auf die Variable SimpleDataFormat synchronisieren?
quelle