使用DecimalFormat和ThreadLocal有什么性能影响?

时间:2017-07-28 09:39:13

标签: java multithreading decimalformat

我有一个使用DecimalFormathttps://docs.oracle.com/javase/7/docs/api/java/text/DecimalFormat.html)API的实现。

Solution1 :参数是因为DecimalFormat 是线程安全的,我倾向于将ThreadLocal用于DecimalFormat创建使其线程安全。此外,它将为每次调用保存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)

什么更好?

2 个答案:

答案 0 :(得分: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秒。除非您的应用程序每秒格式化数百万个字符串,否则不值得考虑: - )

答案 1 :(得分:0)

我想知道是否存在显着差异

  

最近,JVM的性能已成倍增加,因此对象创建不再像以前那样昂贵。

但新的DecimalFormat的分配对内存的影响可能也会消耗时间。 创建新实例非常合理,这就是Java代码的工作原理。

您可以尝试的一件事是预先分配DecimalFormat实例并将它们保存在简单的object pool中。