2010-12-08 99 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"));