Pregunta

Estoy usando joda debido a su buena reputación con respecto a múltiples subprocesos. No hace falta grandes distancias para hacer múltiples fecha roscado manejo eficiente, por ejemplo, haciendo todo Fecha / Hora objetos / DateTime inmutable.

Pero aquí hay una situación en la que no estoy seguro de si Joda está haciendo realmente lo correcto. Probablemente sí, pero estoy muy interesado en ver una explicación.

Cuando un toString () de un DateTime está siendo llamado Joda hace lo siguiente:

/* org.joda.time.base.AbstractInstant */
public String toString() {
    return ISODateTimeFormat.dateTime().print(this);
}

Todos los formateadores son seguros hilo (que inmutables también), pero lo que está sobre el formateador de fábrica:

private static DateTimeFormatter dt;

/*  org.joda.time.format.ISODateTimeFormat */
public static DateTimeFormatter dateTime() {
    if (dt == null) {
        dt = new DateTimeFormatterBuilder()
            .append(date())
            .append(tTime())
            .toFormatter();
    }
    return dt;
}

Este es un patrón común en las aplicaciones roscados individuales pero se sabe que es propenso a errores en un entorno multiproceso.

Veo los siguientes riesgos:

  • Condición de carrera durante el check nula -> peor de los casos:. Dos objetos se crean

No hay problema, ya que esto es únicamente un objeto auxiliar (a diferencia de una situación normal patrón singleton), uno se guarda en dt, el otro está perdido y habrá recolectado antes o después.

  • la variable estática podría apuntar a un objeto parcialmente construido antes de la objec ha sido inicialización acabado

(antes de llamar loco, leer acerca de una situación similar en este artículo de Wikipedia .)

Entonces, ¿cómo asegurarse de que Joda formateador ninguna parcialmente creada se publica en esta variable estática?

Gracias por sus explicaciones!

Reto

¿Fue útil?

Solución

Usted ha dicho, que formateadores son de sólo lectura. Si utilizan sólo los campos finales (no he leído una fuente formateador) y luego en la edición de 3 rd de la especificación del lenguaje Java que sean preservados de la creación de objetos partital por "Semántica campo final". Yo no la salida 2-nd JSL edición y no está seguro, si tal initalization es correcta en esa edición.

Mira el capítulo 17.5 y 17.5.1 de JLS. I wll construir una "cadena de eventos" para requerido sucede-antes de relación.

En primer lugar, en algún lugar en el constructor no es una escritura en el campo final en el formateador. Es la escritura w. Cuando se complete el constructor, una acción de "congelación" tomaron plase. Digamos que es f. En algún lugar más adelante en el orden del programa (después del regreso desde el constructor, tal vez algunos otros métodos y regreso de toFormatter) hay una escritura en el campo dt. Vamos a dar a esta escritura un nombre a. Esta escritura (a) es después de la acción de congelación (f) en el "orden del programa" (orden en la ejecución de un solo roscada) y por lo tanto f sucede-antes de un (hb (f, a)) definición simplemente por JLS. Uf, la inicialización completa ...:)

Somewtimes más tarde, en otro hilo, una llamada a dateTime (). Formato se produce. En ese momento necesitamos dos lecturas. Primero de los dos se lee de la variable final en el objeto formateador. la llamada de Hagámosle r2 (para ser coherente con los JLS). Segundo de los dos es una lectura del "presente" para el formateador. Esto ocurre durante llamada al método dateTime () cuando se lee el campo dt. Y vamos a llamar a esta lectura R1. ¿Qué tenemos ahora? Lectura R1 vio a algunos de escritura en el DT. Considero que esa escritura fue la acción de un párrafo anterior (sólo un hilo escribió ese campo, sólo por simplicidad). Como r1 ver la escritura a, entonces hay mc (a, r1) ( "cadena de memoria" relación, primero definición cláusula). hilo actual no inicializado un formateador, lo lee campo en la acción R2 y ve una "dirección" de un formateador leído en la acción r1. Por lo tanto, por definición, hay un desreferencias (R1, R2) (otra acción de pedido de JLS).

Tenemos escritura antes de la congelación, HB (w, f). Hemos congelar antes de la asignación de la dt, hb (f, a). Tenemos una lectura desde dt, MC (a, r1). Y tenemos una cadena de eliminar la referencia de entre R1 y R2, desreferencias (r1, r2). Todo esto lleva a una sucede antes hb relación (w, r2) con sólo JLS definición. Además, por definición, hb (d, w) donde d es una escritura del valor predeterminado para el campo final en el objeto. Por lo tanto, leer R2 no puede ver de escritura W y tiene que ver escritura r2 (la única escritura en el campo de un código de programa).

Lo mismo es del orden de un acceso más indirecta campo (campo final del objeto almacenado en el campo final, etc ...).

Pero eso no es todo! No hay acceso a un objeto PARCIALMENTE construido. Pero hay un error más interesante. En la ausencia de cualquier fechaHora synhronization explícita () puede devolver nulo. No creo que tal comportamiento puede ser observado en la práctica, pero edición JLS-3 rd no impide que tal comportamiento. Leyó por primera vez del dt campo en el método puede ver un valor inicializado por otro hilo, pero la segunda lectura de la dt puede ver una "escritura de valor defalut". No sucede-antes de las relaciones existe para prevenirlo. Tal comportamiento posible es específico para la edición de 3 rd, segunda edición tiene una "escritura a la memoria principal" / "leer desde la memoria principal" que no permite que un hilo para ver un archivo de valores de la variable en el tiempo de ir.

Otros consejos

Esto es un poco de un no-respuesta, pero la explicación más simple para

  

Entonces, ¿cómo asegurarse de que no Joda formateador parcialmente creada se publica en esta variable estática?

podría ser que no aseguran nada, y cualquiera de los desarrolladores no se dan cuenta de que podría ser un fallo, o pensaron que no valía la pena sincronizan a través de.

hizo una pregunta similar en el Joda lista de correo en 2007, aunque no he encontrado las respuestas para ser concluyente y evité tiempo Joda como resultado, para mejor o peor.

La versión 3 del lenguaje Java Spec garantiza que las actualizaciones de referencia de objetos son atómicas, independientemente de si son de 32 bits o 64 bits. Esto, combinado con los argumentos descritos anteriormente, hace que el hilo de seguridad de la OMI código Joda (ver java.sun.com/docs/books/jls/third_edition/html/memory.html#17.7)

IIRC, la versión 2 de la JLS no incluía la misma aclaración explícita acerca de las referencias a objetos, es decir, sólo los árbitros de 32 bits se les garantizó atómica, por lo que si se utilizara una JVM de 64 bits no había garantía de que iba a funcionar. En el momento que estaba usando Java 1.4, que es anterior a v3 JLS.

OMI el peor de los casos no es dos objetos personales creados, sino varios (tantos como hay hilos de llamada dateTime(), para ser exactos). Desde dateTime() no está sincronizado y dt es ni final, ni volátil, un cambio en su valor en un hilo no se garantiza que sea visible a otros hilos. Así que incluso después de un dt hilo inicializado, cualquier número de otros hilos aún puede ver la referencia como nulo, por lo tanto crear felizmente nuevos objetos.

Aparte de eso, como se explica por otros, un objeto parcialmente creada no puede ser publicado por dateTime(). Ni el (= colgando) de referencia cambiado parcialmente, ya que las actualizaciones de valor de referencia están garantizados para ser atómica.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top