2010-12-08 40 views
21

我必须在许多线程中并行打印许多格式化的十进制值。要格式化小数值,我使用由模式配置的java.text.DecimalFormat。 我知道从DecimalFormat的Java文档的警告:DecimalFormat.format(double)in different threads

十进制格式一般都不会 同步。建议 为每个线程创建 的单独格式实例。如果多个线程 同时访问格式,则必须在外部同步 。

但我不知道这是否警告适用于我的情况:我 配置java.text.DecimalFormat一旦应用程序启动时(并存储Formatter在最终场)。之后我只使用format(double)方法。

我想这样做的原因是:我不想通过每次需要打印格式化数字时创建新的DecimalFormat实例来损失性能。

我看着DecimalFormat.format(double)的代码,它看起来是线程安全的,但我不确定。

请不要更改格式化程序的配置,或者解释为什么不是格式化程序时,请确认DecimalFormat.format(double)的使用最终是线程安全的吗?

+2

A “workarround” 是使用ThreadLocal的,但是是不是问题。 – Ralph 2010-12-08 12:02:39

+0

另一个解决方法是在转换上的DecimalFormat对象上进行同步。 (a)你做了很少的转换,并且同步不会对性能产生太大影响,或者(b)你做了很多转换,在这种情况下,DecimalFormat对象可能会在同一线程中被重复用于转换,因此它们的构建成本应该可以忽略不计。 – 2010-12-08 12:38:53

回答

18

尽管当前的实现可能最终是线程安全的,但是对于即将推出的实现或其他JRE没有这样的保证。

您是否验证过在应用程序中避免new DecimalFormat()是可衡量的性能提升?

+0

在一次测试中,我碰巧发现需要约23ms来实例化NumberFormat和Decimal格式实例,我认为这是一个浪费的执行时间,任何解决方法建议? – 2016-02-03 07:48:25

6

当前DecimalFormat的Hotspot实现会调用DecimalFormat.format(double),如果不调用此实例上的其他方法,则会调用线程。但强烈建议不要依赖这种(可能)暂时的行为。

您是否考虑过使用ThreadLocal变量来避免太多new DecimalFormat()

13

只要使用此线程安全的代码段用于NumberFormat

static ThreadLocal<NumberFormat> numberFormat = new ThreadLocal<NumberFormat>() { 
    @Override 
    public NumberFormat initialValue() { 
     return new DecimalFormat("00000"); 
    } 
}; 

或者用Java 8中,加斯帕在评论说:

private static ThreadLocal<NumberFormat> numberFormatter = 
        ThreadLocal.withInitial(() -> new DecimalFormat("00000"));