Alle warnen davor, dass Java DateFormat nicht threadsicher ist, und ich verstehe das Konzept theoretisch.
Aber ich kann mir nicht vorstellen, mit welchen tatsächlichen Problemen wir aufgrund dessen konfrontiert werden können. Angenommen, ich habe ein DateFormat-Feld in einer Klasse und dasselbe wird in verschiedenen Methoden in der Klasse (Formatieren von Daten) in einer Umgebung mit mehreren Threads verwendet.
Wird dies verursachen:
- jede Ausnahme wie Formatausnahme
- Diskrepanz in Daten
- irgendein anderes Problem?
Erklären Sie bitte auch warum.
java
multithreading
date-format
haps10
quelle
quelle
Antworten:
Probieren wir es aus.
Hier ist ein Programm, in dem mehrere Threads eine gemeinsame Nutzung verwenden
SimpleDateFormat
.Programm :
Führen Sie dies einige Male aus und Sie werden sehen:
Ausnahmen :
Hier einige Beispiele:
1.
2.
3.
Falsche Ergebnisse :
Richtige Ergebnisse :
Ein anderer Ansatz zur sicheren Verwendung von DateFormats in einer Umgebung mit mehreren Threads besteht darin, eine
ThreadLocal
Variable zum Speichern desDateFormat
Objekts zu verwenden. Dies bedeutet, dass jeder Thread eine eigene Kopie hat und nicht warten muss, bis andere Threads sie freigeben. Das ist wie:Hier ist ein guter Beitrag mit mehr Details.
quelle
Ich würde eine Datenbeschädigung erwarten - z. B. wenn Sie zwei Daten gleichzeitig analysieren, könnte ein Anruf durch Daten eines anderen verschmutzt werden.
Es ist leicht vorstellbar, wie dies passieren könnte: Beim Parsen muss häufig ein bestimmter Status für das beibehalten werden, was Sie bisher gelesen haben. Wenn zwei Threads im selben Status trampeln, treten Probleme auf. Zum Beispiel wird
DateFormat
eincalendar
Feld vom TypCalendar
verfügbar gemacht und der CodeSimpleDateFormat
einiger Methodenaufrufecalendar.set(...)
und anderer Aufrufe betrachtetcalendar.get(...)
. Dies ist eindeutig nicht threadsicher.Ich habe nicht genau untersucht, warum
DateFormat
es nicht threadsicher ist, aber für mich ist es genug zu wissen, dass es so ist , ohne Synchronisation unsicher - die genaue Art und Weise von nicht-Sicherheit könnte auch zwischen den Versionen ändern.Persönlich würde ich die Parser aus verwenden Joda Zeit statt, wie sie sind Thread - sicher - und Joda Zeit ist ein viel besseres Datum und Uhrzeit API zu beginnen :)
quelle
Wenn Sie Java 8 verwenden, können Sie verwenden
DateTimeFormatter
.Code:
Ausgabe:
quelle
Grob gesagt, dass Sie keine
DateFormat
als Instanzvariable eines Objekts definieren sollten, auf das viele Threads zugreifen, oderstatic
.Für den Fall, dass
Foo.handleBar(..)
mehrere Threads auf Ihr zugreifen, anstatt:du solltest benutzen:
Außerdem haben Sie in allen Fällen keine
static
DateFormat
Wie von Jon Skeet bemerkt, können Sie sowohl statische als auch gemeinsam genutzte Instanzvariablen haben, falls Sie eine externe Synchronisation durchführen (dh
synchronized
um Aufrufe an dieDateFormat
)quelle
SimpleDateFormat
sehr häufig eine neue zu erstellen . Dies hängt vom Verwendungsmuster ab.Dies bedeutet, dass Sie ein Objekt von DateFormat haben und von zwei verschiedenen Threads auf dasselbe Objekt zugreifen und die Formatmethode für dieses Objekt aufrufen. Beide Threads geben zur gleichen Zeit dieselbe Methode für dasselbe Objekt ein, damit Sie es als gewonnen visualisieren können führt nicht zu einem korrekten Ergebnis
Wenn Sie mit DateFormat arbeiten müssen, sollten Sie etwas tun
quelle
Daten sind beschädigt. Gestern habe ich es in meinem Multithread-Programm bemerkt, wo ich ein statisches
DateFormat
Objekt hatte und esformat()
für Werte aufgerufen habe, die über JDBC gelesen wurden. Ich hatte eine SQL-Select-Anweisung, bei der ich dasselbe Datum mit unterschiedlichen Namen las (SELECT date_from, date_from AS date_from1 ...
). Solche Aussagen wurden in 5 Threads für verschiedene Daten in derWHERE
Klasse verwendet. Die Daten sahen "normal" aus, unterschieden sich jedoch im Wert - während alle Daten aus demselben Jahr stammten, änderten sich nur Monat und Tag.Andere Antworten zeigen Ihnen, wie Sie solche Korruption vermeiden können. Ich habe meine
DateFormat
nicht statisch gemacht, jetzt ist sie Mitglied einer Klasse, die SQL-Anweisungen aufruft. Ich habe auch statische Version mit Synchronisation getestet. Beide funktionierten gut ohne Leistungsunterschied.quelle
Die Spezifikationen von Format, NumberFormat, DateFormat, MessageFormat usw. wurden nicht als threadsicher konzipiert. Außerdem ruft die Analysemethode die Methode auf
Calendar.clone()
und wirkt sich auf die Kalender-Footprints aus, sodass viele Threads, die gleichzeitig analysiert werden, das Klonen der Kalenderinstanz ändern.Weitere Informationen sind Fehlerberichte wie dieser und jener mit Ergebnissen des DateFormat-Thread-Sicherheitsproblems.
quelle
In der besten Antwort gab dogbane ein Beispiel für die Verwendung von
parse
Funktionen und deren Ursachen . Unten finden Sie einen Code, mit dem Sie dieformat
Funktion überprüfen können.Beachten Sie, dass Sie unterschiedliche Ergebnisse erhalten, wenn Sie die Anzahl der Ausführenden (gleichzeitige Threads) ändern. Aus meinen Experimenten:
newFixedThreadPool
5, und die Schleife schlägt jedes Mal fehl.Ich vermute YMMV abhängig von Ihrem Prozessor.
Die
format
Funktion schlägt fehl, indem die Zeit eines anderen Threads formatiert wird. Dies liegt daran, dass die interneformat
Funktion eincalendar
Objekt verwendet, das zu Beginn derformat
Funktion eingerichtet wurde. Und dascalendar
Objekt ist eine Eigenschaft derSimpleDateFormat
Klasse. Seufzer...quelle
Wenn mehrere Threads eine einzelne DateFormat-Instanz bearbeiten / darauf zugreifen und die Synchronisation nicht verwendet wird, können verschlüsselte Ergebnisse erzielt werden. Dies liegt daran, dass mehrere nichtatomare Operationen den Status ändern oder den Speicher inkonsistent sehen können.
quelle
Dies ist mein einfacher Code, der zeigt, dass DateFormat nicht threadsicher ist.
Da alle Threads dasselbe SimpleDateFormat-Objekt verwenden, wird die folgende Ausnahme ausgelöst.
Wenn wir jedoch unterschiedliche Objekte an unterschiedliche Threads übergeben, wird der Code fehlerfrei ausgeführt.
Das sind die Ergebnisse.
quelle
Dies wird verursachen
ArrayIndexOutOfBoundsException
Abgesehen von dem falschen Ergebnis kommt es von Zeit zu Zeit zu einem Absturz. Dies hängt von der Geschwindigkeit Ihrer Maschine ab. In meinem Laptop passiert es durchschnittlich einmal in 100.000 Anrufen:
Die letzte Zeile sollte die verschobene Executor-Ausnahme auslösen:
quelle