On Fri, 4 Mar 2022 21:17:50 GMT, Jim Laskey <[email protected]> wrote:
>> Several attempts have been made to improve Formatter's numeric performance
>> by caching the current Locale zero. Such fixes, however, ignore the real
>> issue, which is the slowness of fetching DecimalFormatSymbols. By directly
>> caching DecimalFormatSymbols in the Formatter, this enhancement streamlines
>> the process of accessing Locale DecimalFormatSymbols and specifically
>> getZeroDigit(). The result is a general improvement in the performance of
>> numeric formatting.
>>
>>
>> @Benchmark
>> public void bigDecimalDefaultLocale() {
>> result = String.format("%1$f %1$f %1$f %1$f %1$f %1$f %1$f %1$f %1$f
>> %1$f", X);
>> }
>>
>> @Benchmark
>> public void bigDecimalLocaleAlternate() {
>> result = String.format(THAI, "%1$f %1$f %1$f %1$f %1$f %1$f %1$f %1$f
>> %1$f %1$f", X);
>> other = String.format(DEFAULT, "%1$f %1$f %1$f %1$f %1$f %1$f %1$f %1$f
>> %1$f %1$f", X);
>> }
>>
>> @Benchmark
>> public void bigDecimalThaiLocale() {
>> result = String.format(THAI, "%1$f %1$f %1$f %1$f %1$f %1$f %1$f %1$f
>> %1$f %1$f", X);
>> }
>>
>> @Benchmark
>> public void integerDefaultLocale() {
>> result = String.format("%1$d %1$d %1$d %1$d %1$d %1$d %1$d %1$d %1$d
>> %1$d", x);
>> }
>>
>> @Benchmark
>> public void integerLocaleAlternate() {
>> result = String.format(THAI, "%1$d %1$d %1$d %1$d %1$d %1$d %1$d %1$d
>> %1$d %1$d", x);
>> other = String.format(DEFAULT, "%1$d %1$d %1$d %1$d %1$d %1$d %1$d %1$d
>> %1$d %1$d", x);
>> }
>>
>> @Benchmark
>> public void integerThaiLocale() {
>> result = String.format(THAI, "%1$d %1$d %1$d %1$d %1$d %1$d %1$d %1$d
>> %1$d %1$d", x);
>> }
>>
>>
>> Before:
>> Benchmark Mode Cnt Score Error Units
>> MyBenchmark.bigDecimalDefaultLocale thrpt 25 75498.923 ± 3686.966 ops/s
>> MyBenchmark.bigDecimalLocaleAlternate thrpt 25 39068.721 ± 162.983 ops/s
>> MyBenchmark.bigDecimalThaiLocale thrpt 25 77256.530 ± 294.743 ops/s
>> MyBenchmark.integerDefaultLocale thrpt 25 344093.071 ± 6189.002 ops/s
>> MyBenchmark.integerLocaleAlternate thrpt 25 165685.488 ± 440.857 ops/s
>> MyBenchmark.integerThaiLocale thrpt 25 327461.302 ± 1168.243 ops/s
>>
>> After:
>> Benchmark Mode Cnt Score Error Units
>> MyBenchmark.bigDecimalDefaultLocale thrpt 25 94735.293 ± 674.587 ops/s
>> MyBenchmark.bigDecimalLocaleAlternate thrpt 25 44215.547 ± 291.664 ops/s
>> MyBenchmark.bigDecimalThaiLocale thrpt 25 91390.997 ± 658.677 ops/s
>> MyBenchmark.integerDefaultLocale thrpt 25 363722.977 ± 2864.554 ops/s
>> MyBenchmark.integerLocaleAlternate thrpt 25 165789.514 ± 779.656 ops/s
>> MyBenchmark.integerThaiLocale thrpt 25 351400.818 ± 1030.246 ops/s
>
> Jim Laskey has updated the pull request incrementally with one additional
> commit since the last revision:
>
> Too many 'the'
src/java.base/share/classes/java/util/Formatter.java line 2012:
> 2010: public final class Formatter implements Closeable, Flushable {
> 2011: // Caching DecimalFormatSymbols
> 2012: static DecimalFormatSymbols DFS = null;
Hello Jim,
The javadoc of `Formatter` states:
>
> Formatters are not necessarily safe for multithreaded access. Thread safety
> is optional and is the responsibility of users of methods in this class.
>
So I would think that user applications would typically be synchronizing on the
instance of a `Formatter` for any multi-threaded use of a formatter instance.
If I'm reading this changed code correctly, it's now possible that 2 separate
instances of a `Formatter` being concurrently accessed (i.e. in different
threads) will now try and update/use this cached class level `static` state
`DFS`. That would thus require some kind of thread safety semantics to be
implemented for this new `getDecimalFormatSymbols(Locale)` method, isn't it?
-------------
PR: https://git.openjdk.java.net/jdk/pull/7703