Java:NumberFormat的同步问题?

Java:NumberFormat的同步问题?,java,Java,我使用java.text.NumberFormat只是简单地将数字转换成可读性更强的字符串,用逗号分隔千位,等等。基本上我将其定义为: public static NumberFormat nf = NumberFormat.getInstance(Locale.US); …然后我只需在任何线程中调用nf.format(some_number),在该线程中我希望生成一个数字的可读版本。但看看JavaDoc,它说:“数字格式通常不同步。建议为每个线程创建单独的格式实例。如果多个线程同时访问一种格

我使用java.text.NumberFormat只是简单地将数字转换成可读性更强的字符串,用逗号分隔千位,等等。基本上我将其定义为:

public static NumberFormat nf = NumberFormat.getInstance(Locale.US);
…然后我只需在任何线程中调用nf.format(some_number),在该线程中我希望生成一个数字的可读版本。但看看JavaDoc,它说:“数字格式通常不同步。建议为每个线程创建单独的格式实例。如果多个线程同时访问一种格式,则必须在外部同步。”

如果我只使用NumberFormat对象的format(number)方法,是否会出现同步问题?我尝试使用NumberFormat.getInstance(Locale.US).format(number)来代替,但每次我觉得可能并不真正需要这样做时,都会有相关的开销。这真的需要外部同步吗?或者有没有一种更简单、更有效的方法来完成同样的事情而不用数字格式


谢谢

使用本地线程。这样,每个线程都将有自己的私有NumberFormat实例,无需进行同步,只需最小的开销。

即使format是您唯一调用的方法,它仍然不是线程安全的。事实上,由于这个原因,我们在工作中遇到了bug。我们通常要么动态创建NumberFormat对象,要么按照Gerco的建议使用ThreadLocal。如果您想了解,可以将NumberFormat子类化,并在format方法中,在对委托NumberFormat调用format之前进行同步,或者使用ThreadLocal检索委托


但是,我认为最直接的方法,尤其是当您要格式化/解析一行中的多个数字时,是手动使用ThreadLocal。

没有理由共享NumberFormat对象。是的,它可能有同步问题(查看您的区域设置的源代码,您将看到它们使用成员变量,甚至用于格式化)。在出现性能问题之前(很可能不会),只需为每次使用创建一个新的问题


编辑正如Michael Borgwardt指出的那样,我对成员变量的直觉是不正确的。不过,为什么要担心呢?使用LocalThread、克隆NumberFormat或创建一个新格式。对象创建的效率不是一个真正的问题大多数时候(但并非总是)

查看
数字格式和
十进制格式的源代码,似乎没有任何字段用于中间结果-唯一的问题是格式本身(例如小数位数)可以通过setter进行更改,因此一个线程可以在另一个线程的
format()
调用被处理时更改它,这当然会导致混乱


如果您从未使用setter,那么它应该是可以的——但当然这只是当前的实现。与API文档相反,我不愿意依赖它。使用
ThreadLocal
听起来是个不错的折衷办法。

NumberFormat
是一个
抽象类。调用
getInstance
时,它的默认值是返回
DecimalFormat
的实例
DecimalFormat
使用一组字段来保持其在格式化过程中的位置,前缀和后缀的模式,
boolean
s指示是否使用指数表示法和千分分组,
int
s描述其整数和分数部分的大小,等等


如果您希望使用任何并发格式,那么
ThreadLocal
选项是一个很好的选择。请注意,
abstract
Format
类的所有子类都被认为是线程不安全的,因此格式化日期也应该非常小心地处理。

我知道这是一个古老的答案,但是。。。你真的不应该去看源代码。即使您知道所使用的Java版本,供应商之间的版本也不相同。(例如,我已经看到IBM和Sun/Oracle JVM之间有很多不同。)在我的JDK版本中,实际上存储了中间结果,但正如您所说的YMMV。使用这种方法进行测量,如果格式化数字是唯一的事情,那么结果在增益时发布实际上是相当可观的。尽管NumberFormat为创建的格式化程序保留缓存,并且在返回它们之前只克隆它们。这同样适用于所有子类。。尤其是日期格式