Todo el mundo advierte que Java DateFormat no es seguro para subprocesos y entiendo el concepto teóricamente.
Pero no puedo visualizar qué problemas reales podemos enfrentar debido a esto. Digamos, tengo un campo DateFormat en una clase y el mismo se usa en diferentes métodos en la clase (fechas de formato) en un entorno de subprocesos múltiples.
¿Esto causará:
- cualquier excepción como excepción de formato
- discrepancia en los datos
- cualquier otro problema?
Además, explique por qué.
java
multithreading
date-format
haps10
fuente
fuente
Respuestas:
Probémoslo.
Aquí hay un programa en el que múltiples hilos usan un compartido
SimpleDateFormat
.Programa :
Ejecute esto varias veces y verá:
Excepciones :
Aquí están algunos ejemplos:
1)
2)
3)
Resultados incorrectos :
Resultados correctos :
Otro enfoque para usar de forma segura DateFormats en un entorno de subprocesos múltiples es usar una
ThreadLocal
variable para contener elDateFormat
objeto, lo que significa que cada subproceso tendrá su propia copia y no necesita esperar a que otros subprocesos lo liberen. Así es como:Aquí hay una buena publicación con más detalles.
fuente
Esperaría la corrupción de datos, por ejemplo, si analiza dos fechas al mismo tiempo, podría tener una llamada contaminada por datos de otra.
Es fácil imaginar cómo podría suceder esto: el análisis a menudo implica mantener una cierta cantidad de estado en cuanto a lo que has leído hasta ahora. Si dos hilos se pisotean en el mismo estado, obtendrá problemas. Por ejemplo,
DateFormat
expone uncalendar
campo de tipoCalendar
y, mirando el código deSimpleDateFormat
, algunos métodos llamancalendar.set(...)
y otros llamancalendar.get(...)
. Esto claramente no es seguro para subprocesos.No he examinado los detalles exactos de por qué
DateFormat
no es seguro para subprocesos, pero para mí es suficiente saber que no es seguro sin sincronización: las formas exactas de no seguridad incluso podrían cambiar entre lanzamientos.Personalmente, usaría los analizadores de Joda Time , ya que son seguros para subprocesos, y Joda Time es una API de fecha y hora mucho mejor para comenzar :)
fuente
Si está utilizando Java 8, puede usarlo
DateTimeFormatter
.Código:
Salida:
fuente
Aproximadamente, que no debe definir una
DateFormat
variable de instancia de un objeto al que acceden muchos hilos, ostatic
.Por lo tanto, en caso
Foo.handleBar(..)
de que varios subprocesos accedan a su, en lugar de:Deberías usar:
Además, en todos los casos, no tengo un
static
DateFormat
Como señaló Jon Skeet, puede tener variables de instancia tanto estáticas como compartidas en caso de que realice una sincronización externa (es decir, use
synchronized
alrededor de llamadas alDateFormat
)fuente
SimpleDateFormat
mucha frecuencia. Dependerá del patrón de uso.Esto significa que suponga que tiene un objeto de DateFormat y está accediendo al mismo objeto desde dos hilos diferentes y está llamando al método de formato sobre ese objeto, ambos hilos ingresarán en el mismo método al mismo tiempo en el mismo objeto para que pueda visualizarlo ganado no resulte en el resultado adecuado
Si tiene que trabajar con DateFormat de alguna manera, entonces debe hacer algo
fuente
Los datos están dañados. Ayer lo noté en mi programa multiproceso donde tenía un
DateFormat
objeto estático y pedí queformat()
leyeran los valores a través de JDBC. Tenía una instrucción de selección SQL donde leía la misma fecha con diferentes nombres (SELECT date_from, date_from AS date_from1 ...
). Dichas declaraciones fueron utilizadas en 5 hilos para varias fechas enWHERE
clase. Las fechas parecían "normales" pero tenían un valor diferente, mientras que todas las fechas eran del mismo año, solo el mes y el día cambiaron.Otras respuestas le muestran el camino para evitar tal corrupción. Hice mi
DateFormat
no estático, ahora es miembro de una clase que llama a las declaraciones SQL. También probé la versión estática con sincronización. Ambos funcionaron bien sin diferencias en el rendimiento.fuente
Las especificaciones de Format, NumberFormat, DateFormat, MessageFormat, etc. no fueron diseñadas para ser seguras para subprocesos. Además, el método de análisis llama al
Calendar.clone()
método y afecta las huellas del calendario, por lo que muchos subprocesos que analizan simultáneamente cambiarán la clonación de la instancia del calendario.Para obtener más información, estos son informes de errores como este y este , con resultados del problema de seguridad de subprocesos de DateFormat.
fuente
En la mejor respuesta, dogbane dio un ejemplo del uso de la
parse
función y a lo que conduce. A continuación hay un código que le permite verificar laformat
función.Tenga en cuenta que si cambia el número de ejecutores (hilos concurrentes) obtendrá resultados diferentes. De mis experimentos:
newFixedThreadPool
en 5 y el bucle fallará siempre.Supongo que YMMV depende de tu procesador.
La
format
función falla formateando el tiempo desde un hilo diferente. Esto se debe a que internamente laformat
función está utilizando uncalendar
objeto que se configura al comienzo de laformat
función. Y elcalendar
objeto es una propiedad de laSimpleDateFormat
clase. Suspiro...fuente
Si hay múltiples hilos manipulando / accediendo a una sola instancia de DateFormat y la sincronización no se usa, es posible obtener resultados codificados. Esto se debe a que varias operaciones no atómicas podrían estar cambiando de estado o viendo la memoria de manera inconsistente.
fuente
Este es mi código simple que muestra que DateFormat no es seguro para subprocesos.
Como todos los hilos están usando el mismo objeto SimpleDateFormat, arroja la siguiente excepción.
Pero si pasamos diferentes objetos a diferentes hilos, el código se ejecuta sin errores.
Estos son los resultados.
fuente
Esto causará
ArrayIndexOutOfBoundsException
Además del resultado incorrecto, ocasionará un bloqueo de vez en cuando. Depende de la velocidad de su máquina; en mi laptop, ocurre una vez en 100,000 llamadas en promedio:
la última línea podría desencadenar la excepción del ejecutor pospuesto:
fuente