2009-08-16 16 views
14

utilizo java.text.NumberFormat simplemente para convertir los números en cadenas más legibles, con comas separación de miles, etc. Básicamente lo defino como:Java: ¿problema de sincronización con NumberFormat?

public static NumberFormat nf = NumberFormat.getInstance(Locale.US); 

... y luego acabo de llamar nf.format (some_number) en cualquier hilo donde quiera hacer una versión legible de un número. Pero mirando el JavaDoc, dice: "Los formatos numéricos generalmente no están sincronizados. Se recomienda crear instancias de formato separadas para cada subproceso. Si varios subprocesos acceden a un formato al mismo tiempo, se debe sincronizar externamente".

Si sólo estoy usando el método de formato (número) del objeto NumberFormat, podría haber alguna vez un problema de sincronización? Intenté usar NumberFormat.getInstance (Locale.US) .format (number) en su lugar, pero hay una sobrecarga asociada con hacer eso cada vez que siento que probablemente no sea realmente necesario. ¿Esto realmente necesita sincronización externa? ¿O hay una forma más simple y eficiente de lograr lo mismo sin NumberFormat?

Gracias!

Respuesta

15

Incluso si el formato es el único método alguna vez llama, todavía no seguro para subprocesos. De hecho, hemos tenido errores en el trabajo debido a esto. Por lo general, creamos objetos NumberFormat sobre la marcha, o usamos un ThreadLocal como sugirió Gerco. Si desea hacerse elegante, puede crear una subclase NumberFormat y en el método de formato, sincronizar antes de llamar al formato en un NumberFormat de delegado o utilizar un ThreadLocal para recuperar un delegado.

Sin embargo, creo que la forma más sencilla, especialmente si vas a formatear/analizar varios números en una fila, es utilizar un ThreadLocal manualmente.

+0

Mide esto usando https://gist.github.com/jontejj/5430320, los resultados se publican en http://1.microbenchmarks.appspot.com/run/[email protected]/se.softhouse .common.numbers.NumberFormatBenchmark la ganancia es bastante considerable si los números de formato son lo único que sucede. Esto a pesar de que NumberFormat mantiene un caché para los formateadores creados y solo los clona antes de devolverlos. – jontejj

+0

Y lo mismo se aplica a todas las subclases ... Especialmente a DateFormat – Snicolas

8

Utilice un NumberFormat ThreadLocal < >. De esta forma, cada subproceso tendrá su propia instancia privada NumberFormat y no habrá necesidad de sincronizar y solo una sobrecarga mínima.

1

No hay ninguna razón para compartir un objeto NumberFormat. Sí, puede tener problemas de sincronización (observe la fuente de su configuración regional y verá que usan variables miembro, incluso para formatear). Hasta que tenga problemas de rendimiento (lo que probablemente no ocurra), simplemente cree uno nuevo para cada uso.

Editar Como Michael Borgwardt señala, mi corazonada sobre variables miembro no era correcta. Aún así, ¿por qué preocuparse? Utiliza LocalThread, clona el NumberFormat o simplemente crea uno nuevo. La eficiencia en términos de creación de objetos no es una preocupación real la mayoría de las veces (pero no siempre).

3

Si examina el código fuente de NumberFormat y DecimalFormat, allí no parece haber ninguna campos utilizados para los resultados intermedios - el único problema es que el formato en sí mismo (por ejemplo, número de dígitos fraccionarios) es mutable a través de los emisores, por lo que uno el hilo podría cambiarlo mientras se está procesando la llamada de otro format(), y eso, por supuesto, provocaría un desastre.

Si nunca usa los ajustadores, entonces debería estar bien, pero por supuesto esta es solo la implementación actual. No me sentiría cómodo con eso en contrario a los documentos de la API. Usar un ThreadLocal suena como un buen compromiso.

+1

Sé que esta es una respuesta antigua, pero ... Realmente no debería recurrir al código fuente. Incluso si sabe qué versión de Java está utilizando, es diferente entre proveedores. (He visto muchas diferencias entre IBM y Sun/Oracle JVM, por ejemplo.) –

+0

En mi versión del JDK, en realidad hay resultados intermedios almacenados, pero como dijiste YMMV. – jontejj

2

NumberFormat es un abstract class. Su valor predeterminado al llamar al getInstance es devolver una instancia de DecimalFormat.DecimalFormat usa un grupo de campos para mantener su posición dentro de su proceso de formateo, patrones para prefijos y sufijos, boolean s que indican si se debe usar notación exponencial y miles de agrupaciones, int para describir el tamaño de sus partes enteras y fraccionadas, etc.

La opción ThreadLocal es una forma excelente de hacerlo si espera algún formato concurrente. Tenga en cuenta que todas las subclases de la clase abstractFormat se consideran no seguras para subprocesos, por lo que las fechas de formateo también deben manejarse con tanto cuidado.

Cuestiones relacionadas