2017-07-28 51 views
0

我有一個使用DecimalFormathttps://docs.oracle.com/javase/7/docs/api/java/text/DecimalFormat.html)API的實現。使用DecimalFormat和ThreadLocal的性能影響是什麼?

解決方法1:該參數是因爲DecimalFormat線程安全的,我傾向於使用ThreadLocalDecimalFormat創作,使其線程安全的。此外,這將節省的DecimalFormat對象的創建每次調用

private static final ThreadLocal<DecimalFormat> restrictTo1DecimalPlace = 
      ThreadLocal.withInitial 
        (() -> new DecimalFormat("0.0%", DecimalFormatSymbols.getInstance(Locale.ENGLISH))); 

解決方案2:另一種簡單的解決方法是放棄對象的可重用性和創造DecimalFormat每次的對象。

new DecimalFormat("0.0%", DecimalFormatSymbols.getInstance(Locale.ENGLISH)).format(decimalValueToFormat) 

有什麼更好?

+4

除非你能證明第二個導致真正的性能問題,這是非常不可能的,保持簡單,創​​建一個新的,當你需要它。 –

+0

創建新的實例。如果你證明對你的用例來說很慢,那麼考慮使用ThreadLocal。 ThreadLocal的複雜性在於,當線程被銷燬時,必須確保清除ThreadLocal,否則可能導致內存泄漏。 – Augusto

+0

@August如果線程被破壞,清理不成問題,這是一個問題,當它是池中的一個線程時,可用於其他任務。關聯的ThreadLocal內容不能被垃圾收集,但它也不再使用。 – bowmore

回答

1

在大多數應用中,差別都不會有問題,所以你要更簡單的選擇。

public abstract class Benchmark { 

    public static void main(String[] args) throws Exception { 
     final ThreadLocal<DecimalFormat> restrictTo1DecimalPlace = 
       ThreadLocal.withInitial 
         (() -> new DecimalFormat("0.0%", DecimalFormatSymbols.getInstance(Locale.ENGLISH)));    
     Benchmark[] marks = { 
      new Benchmark("ThreadLocal") { 
       @Override 
       protected Object run(int iterations) throws Throwable { 
        StringBuilder sb = new StringBuilder(); 
        for (int i = 0; i < iterations; i++) { 
         sb.append(restrictTo1DecimalPlace.get().format(i * 0.01)); 
        } 
        return sb; 
       }; 
      }, 
      new Benchmark("new Format") { 
       @Override 
       protected Object run(int iterations) throws Throwable { 
        StringBuilder sb = new StringBuilder(); 
        for (int i = 0; i < iterations; i++) { 
         sb.append(new DecimalFormat("0.0%", DecimalFormatSymbols.getInstance(Locale.ENGLISH)).format(i * 0.01)); 
        } 
        return sb; 
       }; 
      }, 
     }; 
     for (Benchmark mark : marks) { 
      System.out.println(mark); 
     } 
    } 

    final String name; 

    public Benchmark(String name) { 
     this.name = name; 
    } 

    @Override 
    public String toString() { 
     return name + "\t" + time() + " ns/iteration"; 
    } 

    private BigDecimal time() { 
     try { 
      // automatically detect a reasonable iteration count (and trigger just in time compilation of the code under test) 
      int iterations; 
      long duration = 0; 
      for (iterations = 1; iterations < 1_000_000_000 && duration < 1_000_000_000; iterations *= 2) { 
       long start = System.nanoTime(); 
       run(iterations); 
       duration = System.nanoTime() - start; 
      } 
      return new BigDecimal((duration) * 1000/iterations).movePointLeft(3); 
     } catch (Throwable e) { 
      throw new RuntimeException(e); 
     } 
    } 

    /** 
    * Executes the code under test. 
    * @param iterations 
    *   number of iterations to perform 
    * @return any value that requires the entire code to be executed (to 
    *   prevent dead code elimination by the just in time compiler) 
    * @throws Throwable 
    *    if the test could not complete successfully 
    */ 
    protected abstract Object run(int iterations) throws Throwable; 
} 

在我的機器,這個打印:

ThreadLocal 260.132 ns/iteration 
new Format 363.199 ns/iteration 

所以正從一個ThreadLocal的格式或創建一個新的差異

您可以通過基準測試兩種方案進行驗證大約0.0000001秒。除非你的應用格式字符串百萬每秒,這是不值得考慮:-)

0

我不知道是否有顯著差異

最近,JVM性能已經乘歧管等創建對象不再被認爲是昂貴的,因爲它前面做的。

但的確,新DecimalFormat的分配具有內存影響,也可能消耗時間。 創建新實例是非常合理的,這就是java代碼應該如何工作。

有一兩件事你可以嘗試是預先分配DecimalFormat的情況下,讓他們在一個簡單的object pool

+0

即使創建池,我又回到了原點,即作爲DecimalFormat的不是線程安全的,這意味着當你從你的對象只使用一個線程池借用的DecimalFormat左狀態可以離開進一步影響 – Vishal

+0

。 – ApriOri

+0

比每個新線程都會創建一個我想避免的新對象。 – Vishal

相關問題