Tout le monde met en garde contre le fait que Java DateFormat n'est pas thread-safe et je comprends le concept en théorie.
Mais je ne suis pas en mesure de visualiser les problèmes réels auxquels nous pouvons faire face à cause de cela. Dites, j'ai un champ DateFormat dans une classe et le même est utilisé dans différentes méthodes de la classe (formatage des dates) dans un environnement multi-thread.
Cela causera-t-il:
- toute exception comme l'exception de format
- écart dans les données
- un autre problème?
Veuillez également expliquer pourquoi.
java
multithreading
date-format
haps10
la source
la source
Réponses:
Essayons-le.
Voici un programme dans lequel plusieurs threads utilisent un fichier shared
SimpleDateFormat
.Programme :
Exécutez ceci plusieurs fois et vous verrez:
Exceptions :
Voici quelques exemples:
1.
2.
3.
Résultats incorrects :
Résultats corrects :
Une autre approche pour utiliser en toute sécurité DateFormats dans un environnement multi-thread consiste à utiliser une
ThreadLocal
variable pour contenir l'DateFormat
objet, ce qui signifie que chaque thread aura sa propre copie et n'a pas besoin d'attendre que d'autres threads le libèrent. C'est ainsi:Voici un bon article avec plus de détails.
la source
Je m'attendrais à une corruption des données - par exemple, si vous analysez deux dates en même temps, vous pourriez avoir un appel pollué par les données d'un autre.
Il est facile d'imaginer comment cela pourrait se produire: l'analyse consiste souvent à maintenir un certain état de ce que vous avez lu jusqu'à présent. Si deux threads piétinent tous les deux le même état, vous aurez des problèmes. Par exemple,
DateFormat
expose uncalendar
champ de typeCalendar
, et en regardant le code deSimpleDateFormat
, certaines méthodes appellentcalendar.set(...)
et d'autres appellentcalendar.get(...)
. Ce n'est clairement pas sûr pour les threads.Je n'ai pas examiné les détails exacts de la raison pour laquelle les
DateFormat
threads ne sont pas sécurisés, mais pour moi, il suffit de savoir que ce n'est pas sûr sans synchronisation - les manières exactes de non-sécurité pourraient même changer entre les versions.Personnellement, j'utiliserais plutôt les analyseurs de Joda Time , car ils sont thread-safe - et Joda Time est une bien meilleure API de date et d'heure pour commencer :)
la source
Si vous utilisez Java 8, vous pouvez utiliser
DateTimeFormatter
.Code:
Production:
la source
En gros, vous ne devez pas définir une
DateFormat
variable comme instance d'un objet auquel accèdent de nombreux threads, oustatic
.Donc, dans le cas où vous
Foo.handleBar(..)
êtes accédé par plusieurs threads, au lieu de:Tu devrais utiliser:
De plus, dans tous les cas, ne disposez pas
static
DateFormat
Comme indiqué par Jon Skeet, vous pouvez avoir à la fois des variables d'instance statiques et partagées au cas où vous effectuez une synchronisation externe (c'est-à-dire à utiliser
synchronized
autour des appels à laDateFormat
)la source
SimpleDateFormat
très fréquemment. Cela dépendra du modèle d'utilisation.Cela signifie que vous avez un objet DateFormat et que vous accédez au même objet à partir de deux threads différents et que vous appelez la méthode de format sur cet objet, les deux threads entreront sur la même méthode en même temps sur le même objet afin que vous puissiez le visualiser gagné ne résultera pas en un résultat correct
Si vous devez travailler avec DateFormat de quelque manière que ce soit, vous devez faire quelque chose
la source
Les données sont corrompues. Hier, je l'ai remarqué dans mon programme multithread où j'avais un
DateFormat
objet statique et l' ai appeléformat()
pour les valeurs lues via JDBC. J'ai eu l'instruction de sélection SQL où j'ai lu la même date avec des noms différents (SELECT date_from, date_from AS date_from1 ...
). Ces déclarations étaient utilisées dans 5 threads pour différentes dates enWHERE
clasue. Les dates semblaient «normales» mais leur valeur différait - alors que toutes les dates étaient de la même année, seuls le mois et le jour changeaient.D'autres réponses vous montrent le moyen d'éviter une telle corruption. J'ai fait mon
DateFormat
pas statique, maintenant c'est un membre d'une classe qui appelle des instructions SQL. J'ai testé aussi la version statique avec synchronisation. Les deux ont bien fonctionné sans aucune différence de performance.la source
Les spécifications de Format, NumberFormat, DateFormat, MessageFormat, etc. n'ont pas été conçues pour être thread-safe. En outre, la méthode parse appelle la
Calendar.clone()
méthode et affecte les empreintes de calendrier, de sorte que de nombreux threads analysés simultanément modifieront le clonage de l'instance de calendrier.Pour plus, il s'agit de rapports de bogues tels que celui-ci et celui-ci , avec les résultats du problème de sécurité des threads de DateFormat.
la source
Dans la meilleure réponse, dogbane a donné un exemple d'utilisation de la
parse
fonction et ce à quoi elle mène. Voici un code qui vous permet de vérifier laformat
fonction.Notez que si vous modifiez le nombre d'exécuteurs (threads simultanés), vous obtiendrez des résultats différents. De mes expériences:
newFixedThreadPool
la valeur 5 et la boucle échouera à chaque fois.Je suppose que YMMV dépend de votre processeur.
La
format
fonction échoue en formatant l'heure à partir d'un thread différent. En effet, laformat
fonction interne utilise uncalendar
objet qui est configuré au début de laformat
fonction. Et l'calendar
objet est une propriété de laSimpleDateFormat
classe. Soupir...la source
Si plusieurs threads manipulent / accèdent à une seule instance de DateFormat et que la synchronisation n'est pas utilisée, il est possible d'obtenir des résultats brouillés. C'est parce que plusieurs opérations non atomiques peuvent changer d'état ou voir la mémoire de manière incohérente.
la source
Ceci est mon code simple qui montre que DateFormat n'est pas thread-safe.
Étant donné que tous les threads utilisent le même objet SimpleDateFormat, il lève l'exception suivante.
Mais si nous transmettons différents objets à différents threads, le code s'exécute sans erreur.
Voici les résultats.
la source
Cela causera
ArrayIndexOutOfBoundsException
Mis à part le résultat incorrect, cela vous causera un crash de temps en temps. Cela dépend de la vitesse de votre machine; dans mon ordinateur portable, cela se produit une fois sur 100000 appels en moyenne:
la dernière ligne devrait déclencher l'exception de l'exécuteur reporté:
la source