From c73e706f5cad52fcba3296c5b4b03da7524f7cba Mon Sep 17 00:00:00 2001 From: Shaojin Wen Date: Wed, 16 Jul 2025 18:36:50 +0800 Subject: [PATCH 01/10] LocaleProviderAdapter$Type::adapter Stable --- .../provider/LocaleProviderAdapter.java | 81 +++++++------------ 1 file changed, 31 insertions(+), 50 deletions(-) diff --git a/src/java.base/share/classes/sun/util/locale/provider/LocaleProviderAdapter.java b/src/java.base/share/classes/sun/util/locale/provider/LocaleProviderAdapter.java index 5e7a4c719d160..9d2ad0d4b7d8b 100644 --- a/src/java.base/share/classes/sun/util/locale/provider/LocaleProviderAdapter.java +++ b/src/java.base/share/classes/sun/util/locale/provider/LocaleProviderAdapter.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -73,6 +73,7 @@ public enum Type { private final String CLASSNAME; private final String UTIL_RESOURCES_PACKAGE; private final String TEXT_RESOURCES_PACKAGE; + private final StableValue adapter = StableValue.of(); Type(String className) { this(className, null, null); @@ -95,6 +96,25 @@ public String getUtilResourcesPackage() { public String getTextResourcesPackage() { return TEXT_RESOURCES_PACKAGE; } + + public LocaleProviderAdapter getAdapter() { + return adapter.orElseSet(() -> { + var type = Type.this; + try { + // lazily load adapters here + return (LocaleProviderAdapter)Class.forName(type.getAdapterClassName()) + .getDeclaredConstructor().newInstance(); + } catch (NoSuchMethodException | + InvocationTargetException | + ClassNotFoundException | + IllegalAccessException | + InstantiationException | + UnsupportedOperationException e) { + throw new ServiceConfigurationError("Locale provider adapter \"" + + type + "\"cannot be instantiated.", e); + } + }); + } } /** @@ -102,11 +122,6 @@ public String getTextResourcesPackage() { */ private static final List adapterPreference; - /** - * LocaleProviderAdapter instances - */ - private static final Map adapterInstances = new ConcurrentHashMap<>(); - /** * Adapter lookup cache. */ @@ -167,49 +182,17 @@ public String getTextResourcesPackage() { * Returns the singleton instance for each adapter type */ public static LocaleProviderAdapter forType(Type type) { - switch (type) { - case JRE: - case CLDR: - case SPI: - case HOST: - case FALLBACK: - LocaleProviderAdapter adapter = adapterInstances.get(type); - if (adapter == null) { - try { - // lazily load adapters here - adapter = (LocaleProviderAdapter)Class.forName(type.getAdapterClassName()) - .getDeclaredConstructor().newInstance(); - LocaleProviderAdapter cached = adapterInstances.putIfAbsent(type, adapter); - if (cached != null) { - adapter = cached; - } - } catch (NoSuchMethodException | - InvocationTargetException | - ClassNotFoundException | - IllegalAccessException | - InstantiationException | - UnsupportedOperationException e) { - throw new ServiceConfigurationError("Locale provider adapter \"" + - type + "\"cannot be instantiated.", e); - } - } - return adapter; - default: - throw new InternalError("unknown locale data adapter type"); - } + return type.getAdapter(); } public static LocaleProviderAdapter forJRE() { - return forType(Type.JRE); + return Type.JRE.getAdapter(); } public static LocaleProviderAdapter getResourceBundleBased() { for (Type type : getAdapterPreference()) { if (type == Type.JRE || type == Type.CLDR || type == Type.FALLBACK) { - LocaleProviderAdapter adapter = forType(type); - if (adapter != null) { - return adapter; - } + return type.getAdapter(); } } // Shouldn't happen. @@ -270,20 +253,18 @@ public static LocaleProviderAdapter getAdapter(Class providerClass, Locale locale) { for (Type type : getAdapterPreference()) { - LocaleProviderAdapter adapter = forType(type); - if (adapter != null) { - LocaleServiceProvider provider = adapter.getLocaleServiceProvider(providerClass); - if (provider != null) { - if (provider.isSupportedLocale(locale)) { - return adapter; - } + LocaleProviderAdapter adapter = type.getAdapter(); + LocaleServiceProvider provider = adapter.getLocaleServiceProvider(providerClass); + if (provider != null) { + if (provider.isSupportedLocale(locale)) { + return adapter; } } } From baf2193693945956d84a40beb66141eba6ccd26d Mon Sep 17 00:00:00 2001 From: Shaojin Wen Date: Wed, 16 Jul 2025 19:45:22 +0800 Subject: [PATCH 02/10] LocaleProviderAdapter StableValue --- .../util/cldr/CLDRLocaleProviderAdapter.java | 45 +--- .../FallbackLocaleProviderAdapter.java | 17 +- .../provider/JRELocaleProviderAdapter.java | 225 +++++------------- 3 files changed, 67 insertions(+), 220 deletions(-) diff --git a/src/java.base/share/classes/sun/util/cldr/CLDRLocaleProviderAdapter.java b/src/java.base/share/classes/sun/util/cldr/CLDRLocaleProviderAdapter.java index 573187ba3d0cd..e63bca11dd81f 100644 --- a/src/java.base/share/classes/sun/util/cldr/CLDRLocaleProviderAdapter.java +++ b/src/java.base/share/classes/sun/util/cldr/CLDRLocaleProviderAdapter.java @@ -97,34 +97,16 @@ public BreakIteratorProvider getBreakIteratorProvider() { @Override public CalendarDataProvider getCalendarDataProvider() { - if (calendarDataProvider == null) { - CalendarDataProvider provider = new CLDRCalendarDataProviderImpl( - getAdapterType(), - getLanguageTagSet("CalendarData")); - - synchronized (this) { - if (calendarDataProvider == null) { - calendarDataProvider = provider; - } - } - } - return calendarDataProvider; + return calendarDataProvider.orElseSet(() -> new CLDRCalendarDataProviderImpl( + getAdapterType(), + getLanguageTagSet("CalendarData"))); } @Override public CalendarNameProvider getCalendarNameProvider() { - if (calendarNameProvider == null) { - CalendarNameProvider provider = new CLDRCalendarNameProviderImpl( - getAdapterType(), - getLanguageTagSet("FormatData")); - - synchronized (this) { - if (calendarNameProvider == null) { - calendarNameProvider = provider; - } - } - } - return calendarNameProvider; + return calendarNameProvider.orElseSet(() -> new CLDRCalendarNameProviderImpl( + getAdapterType(), + getLanguageTagSet("FormatData"))); } @Override @@ -134,18 +116,9 @@ public CollatorProvider getCollatorProvider() { @Override public TimeZoneNameProvider getTimeZoneNameProvider() { - if (timeZoneNameProvider == null) { - TimeZoneNameProvider provider = new CLDRTimeZoneNameProviderImpl( - getAdapterType(), - getLanguageTagSet("TimeZoneNames")); - - synchronized (this) { - if (timeZoneNameProvider == null) { - timeZoneNameProvider = provider; - } - } - } - return timeZoneNameProvider; + return timeZoneNameProvider.orElseSet(() -> new CLDRTimeZoneNameProviderImpl( + getAdapterType(), + getLanguageTagSet("TimeZoneNames"))); } @Override diff --git a/src/java.base/share/classes/sun/util/locale/provider/FallbackLocaleProviderAdapter.java b/src/java.base/share/classes/sun/util/locale/provider/FallbackLocaleProviderAdapter.java index 0637be76781eb..a919f97454641 100644 --- a/src/java.base/share/classes/sun/util/locale/provider/FallbackLocaleProviderAdapter.java +++ b/src/java.base/share/classes/sun/util/locale/provider/FallbackLocaleProviderAdapter.java @@ -46,7 +46,7 @@ public class FallbackLocaleProviderAdapter extends JRELocaleProviderAdapter { private static final Locale[] AVAILABLE_LOCS = {Locale.US, Locale.ENGLISH, Locale.ROOT}; private static final Set AVAILABLE_LANGTAGS = Set.of("en-US", "en", "und"); - private volatile BreakIteratorProvider breakIteratorProvider; + private final StableValue breakIteratorProvider = StableValue.of(); /** * Returns the type of this LocaleProviderAdapter @@ -82,17 +82,8 @@ public boolean isSupportedProviderLocale(Locale locale, Set langtags) { @Override // In order to correctly report supported locales public BreakIteratorProvider getBreakIteratorProvider() { - if (breakIteratorProvider == null) { - BreakIteratorProvider provider = new BreakIteratorProviderImpl( - getAdapterType(), - getLanguageTagSet("BreakIteratorRules")); - - synchronized (this) { - if (breakIteratorProvider == null) { - breakIteratorProvider = provider; - } - } - } - return breakIteratorProvider; + return breakIteratorProvider.orElseSet(() -> new BreakIteratorProviderImpl( + getAdapterType(), + getLanguageTagSet("BreakIteratorRules"))); } } diff --git a/src/java.base/share/classes/sun/util/locale/provider/JRELocaleProviderAdapter.java b/src/java.base/share/classes/sun/util/locale/provider/JRELocaleProviderAdapter.java index 14d36f0e266db..b579dd8db9697 100644 --- a/src/java.base/share/classes/sun/util/locale/provider/JRELocaleProviderAdapter.java +++ b/src/java.base/share/classes/sun/util/locale/provider/JRELocaleProviderAdapter.java @@ -113,119 +113,65 @@ public

P getLocaleServiceProvider(Class

c) } } - private volatile BreakIteratorProvider breakIteratorProvider; - private volatile CollatorProvider collatorProvider; - private volatile DateFormatProvider dateFormatProvider; - private volatile DateFormatSymbolsProvider dateFormatSymbolsProvider; - private volatile DecimalFormatSymbolsProvider decimalFormatSymbolsProvider; - private volatile NumberFormatProvider numberFormatProvider; - - private volatile CurrencyNameProvider currencyNameProvider; - private volatile LocaleNameProvider localeNameProvider; - protected volatile TimeZoneNameProvider timeZoneNameProvider; - protected volatile CalendarDataProvider calendarDataProvider; - protected volatile CalendarNameProvider calendarNameProvider; - - private volatile CalendarProvider calendarProvider; - private volatile JavaTimeDateTimePatternProvider javaTimeDateTimePatternProvider; + private final StableValue breakIteratorProvider = StableValue.of(); + private final StableValue collatorProvider = StableValue.of(); + private final StableValue dateFormatProvider = StableValue.of(); + private final StableValue dateFormatSymbolsProvider = StableValue.of(); + private final StableValue decimalFormatSymbolsProvider = StableValue.of(); + private final StableValue numberFormatProvider = StableValue.of(); + + private final StableValue currencyNameProvider = StableValue.of(); + private final StableValue localeNameProvider = StableValue.of(); + protected final StableValue timeZoneNameProvider = StableValue.of(); + protected final StableValue calendarDataProvider = StableValue.of(); + protected final StableValue calendarNameProvider = StableValue.of(); + + private final StableValue calendarProvider = StableValue.of(); + private final StableValue javaTimeDateTimePatternProvider = StableValue.of(); /* * Getter methods for java.text.spi.* providers */ @Override public BreakIteratorProvider getBreakIteratorProvider() { - if (breakIteratorProvider == null) { - BreakIteratorProvider provider = new BreakIteratorProviderImpl( - getAdapterType(), - getLanguageTagSet("FormatData")); - - synchronized (this) { - if (breakIteratorProvider == null) { - breakIteratorProvider = provider; - } - } - } - return breakIteratorProvider; + return breakIteratorProvider.orElseSet(() -> new BreakIteratorProviderImpl( + getAdapterType(), + getLanguageTagSet("FormatData"))); } @Override public CollatorProvider getCollatorProvider() { - if (collatorProvider == null) { - CollatorProvider provider = new CollatorProviderImpl( - getAdapterType(), - getLanguageTagSet("CollationData")); - - synchronized (this) { - if (collatorProvider == null) { - collatorProvider = provider; - } - } - } - return collatorProvider; + return collatorProvider.orElseSet(() -> new CollatorProviderImpl( + getAdapterType(), + getLanguageTagSet("CollationData"))); } @Override public DateFormatProvider getDateFormatProvider() { - if (dateFormatProvider == null) { - DateFormatProvider provider = new DateFormatProviderImpl( - getAdapterType(), - getLanguageTagSet("FormatData")); - - synchronized (this) { - if (dateFormatProvider == null) { - dateFormatProvider = provider; - } - } - } - return dateFormatProvider; + return dateFormatProvider.orElseSet(() -> new DateFormatProviderImpl( + getAdapterType(), + getLanguageTagSet("FormatData"))); } @Override public DateFormatSymbolsProvider getDateFormatSymbolsProvider() { - if (dateFormatSymbolsProvider == null) { - DateFormatSymbolsProvider provider = new DateFormatSymbolsProviderImpl( - getAdapterType(), - getLanguageTagSet("FormatData")); - - synchronized (this) { - if (dateFormatSymbolsProvider == null) { - dateFormatSymbolsProvider = provider; - } - } - } - return dateFormatSymbolsProvider; + return dateFormatSymbolsProvider.orElseSet(() -> new DateFormatSymbolsProviderImpl( + getAdapterType(), + getLanguageTagSet("FormatData"))); } @Override public DecimalFormatSymbolsProvider getDecimalFormatSymbolsProvider() { - if (decimalFormatSymbolsProvider == null) { - DecimalFormatSymbolsProvider provider = new DecimalFormatSymbolsProviderImpl( - getAdapterType(), - getLanguageTagSet("FormatData")); - - synchronized (this) { - if (decimalFormatSymbolsProvider == null) { - decimalFormatSymbolsProvider = provider; - } - } - } - return decimalFormatSymbolsProvider; + return decimalFormatSymbolsProvider.orElseSet(() -> new DecimalFormatSymbolsProviderImpl( + getAdapterType(), + getLanguageTagSet("FormatData"))); } @Override public NumberFormatProvider getNumberFormatProvider() { - if (numberFormatProvider == null) { - NumberFormatProvider provider = new NumberFormatProviderImpl( - getAdapterType(), - getLanguageTagSet("FormatData")); - - synchronized (this) { - if (numberFormatProvider == null) { - numberFormatProvider = provider; - } - } - } - return numberFormatProvider; + return numberFormatProvider.orElseSet(() -> new NumberFormatProviderImpl( + getAdapterType(), + getLanguageTagSet("FormatData"))); } /** @@ -233,82 +179,37 @@ public NumberFormatProvider getNumberFormatProvider() { */ @Override public CurrencyNameProvider getCurrencyNameProvider() { - if (currencyNameProvider == null) { - CurrencyNameProvider provider = new CurrencyNameProviderImpl( - getAdapterType(), - getLanguageTagSet("CurrencyNames")); - - synchronized (this) { - if (currencyNameProvider == null) { - currencyNameProvider = provider; - } - } - } - return currencyNameProvider; + return currencyNameProvider.orElseSet(() -> new CurrencyNameProviderImpl( + getAdapterType(), + getLanguageTagSet("CurrencyNames"))); } @Override public LocaleNameProvider getLocaleNameProvider() { - if (localeNameProvider == null) { - LocaleNameProvider provider = new LocaleNameProviderImpl( - getAdapterType(), - getLanguageTagSet("LocaleNames")); - - synchronized (this) { - if (localeNameProvider == null) { - localeNameProvider = provider; - } - } - } - return localeNameProvider; + return localeNameProvider.orElseSet(() -> new LocaleNameProviderImpl( + getAdapterType(), + getLanguageTagSet("LocaleNames"))); } @Override public TimeZoneNameProvider getTimeZoneNameProvider() { - if (timeZoneNameProvider == null) { - TimeZoneNameProvider provider = new TimeZoneNameProviderImpl( - getAdapterType(), - getLanguageTagSet("TimeZoneNames")); - - synchronized (this) { - if (timeZoneNameProvider == null) { - timeZoneNameProvider = provider; - } - } - } - return timeZoneNameProvider; + return timeZoneNameProvider.orElseSet(() -> new TimeZoneNameProviderImpl( + getAdapterType(), + getLanguageTagSet("TimeZoneNames"))); } @Override public CalendarDataProvider getCalendarDataProvider() { - if (calendarDataProvider == null) { - CalendarDataProvider provider = new CalendarDataProviderImpl( - getAdapterType(), - getLanguageTagSet("CalendarData")); - - synchronized (this) { - if (calendarDataProvider == null) { - calendarDataProvider = provider; - } - } - } - return calendarDataProvider; + return calendarDataProvider.orElseSet(() -> new CalendarDataProviderImpl( + getAdapterType(), + getLanguageTagSet("CalendarData"))); } @Override public CalendarNameProvider getCalendarNameProvider() { - if (calendarNameProvider == null) { - CalendarNameProvider provider = new CalendarNameProviderImpl( - getAdapterType(), - getLanguageTagSet("FormatData")); - - synchronized (this) { - if (calendarNameProvider == null) { - calendarNameProvider = provider; - } - } - } - return calendarNameProvider; + return calendarNameProvider.orElseSet(() -> new CalendarNameProviderImpl( + getAdapterType(), + getLanguageTagSet("FormatData"))); } /** @@ -316,18 +217,9 @@ public CalendarNameProvider getCalendarNameProvider() { */ @Override public CalendarProvider getCalendarProvider() { - if (calendarProvider == null) { - CalendarProvider provider = new CalendarProviderImpl( - getAdapterType(), - getLanguageTagSet("CalendarData")); - - synchronized (this) { - if (calendarProvider == null) { - calendarProvider = provider; - } - } - } - return calendarProvider; + return calendarProvider.orElseSet(() -> new CalendarProviderImpl( + getAdapterType(), + getLanguageTagSet("CalendarData"))); } /** @@ -335,18 +227,9 @@ public CalendarProvider getCalendarProvider() { */ @Override public JavaTimeDateTimePatternProvider getJavaTimeDateTimePatternProvider() { - if (javaTimeDateTimePatternProvider == null) { - JavaTimeDateTimePatternProvider provider = new JavaTimeDateTimePatternImpl( - getAdapterType(), - getLanguageTagSet("FormatData")); - - synchronized (this) { - if (javaTimeDateTimePatternProvider == null) { - javaTimeDateTimePatternProvider = provider; - } - } - } - return javaTimeDateTimePatternProvider; + return javaTimeDateTimePatternProvider.orElseSet(() -> new JavaTimeDateTimePatternImpl( + getAdapterType(), + getLanguageTagSet("FormatData"))); } @Override From 38bd988be4d0924b919bed803c48127c10d50688 Mon Sep 17 00:00:00 2001 From: Shaojin Wen Date: Wed, 16 Jul 2025 20:34:51 +0800 Subject: [PATCH 03/10] copyright --- .../share/classes/sun/util/cldr/CLDRLocaleProviderAdapter.java | 2 +- .../sun/util/locale/provider/FallbackLocaleProviderAdapter.java | 2 +- .../sun/util/locale/provider/JRELocaleProviderAdapter.java | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/java.base/share/classes/sun/util/cldr/CLDRLocaleProviderAdapter.java b/src/java.base/share/classes/sun/util/cldr/CLDRLocaleProviderAdapter.java index e63bca11dd81f..02a8ce29a0eb3 100644 --- a/src/java.base/share/classes/sun/util/cldr/CLDRLocaleProviderAdapter.java +++ b/src/java.base/share/classes/sun/util/cldr/CLDRLocaleProviderAdapter.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it diff --git a/src/java.base/share/classes/sun/util/locale/provider/FallbackLocaleProviderAdapter.java b/src/java.base/share/classes/sun/util/locale/provider/FallbackLocaleProviderAdapter.java index a919f97454641..aaf0b4fe9a421 100644 --- a/src/java.base/share/classes/sun/util/locale/provider/FallbackLocaleProviderAdapter.java +++ b/src/java.base/share/classes/sun/util/locale/provider/FallbackLocaleProviderAdapter.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it diff --git a/src/java.base/share/classes/sun/util/locale/provider/JRELocaleProviderAdapter.java b/src/java.base/share/classes/sun/util/locale/provider/JRELocaleProviderAdapter.java index b579dd8db9697..f5bafef7c4719 100644 --- a/src/java.base/share/classes/sun/util/locale/provider/JRELocaleProviderAdapter.java +++ b/src/java.base/share/classes/sun/util/locale/provider/JRELocaleProviderAdapter.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it From dcf6b7d634c74ea2de6f9a39d65a321f490c746a Mon Sep 17 00:00:00 2001 From: Shaojin Wen Date: Thu, 17 Jul 2025 01:30:37 +0800 Subject: [PATCH 04/10] JRELocaleProviderAdapter::localeData StableValue --- .../locale/provider/JRELocaleProviderAdapter.java | 11 ++--------- 1 file changed, 2 insertions(+), 9 deletions(-) diff --git a/src/java.base/share/classes/sun/util/locale/provider/JRELocaleProviderAdapter.java b/src/java.base/share/classes/sun/util/locale/provider/JRELocaleProviderAdapter.java index f5bafef7c4719..5441d05d5888a 100644 --- a/src/java.base/share/classes/sun/util/locale/provider/JRELocaleProviderAdapter.java +++ b/src/java.base/share/classes/sun/util/locale/provider/JRELocaleProviderAdapter.java @@ -65,7 +65,7 @@ public class JRELocaleProviderAdapter extends LocaleProviderAdapter implements R = new ConcurrentHashMap<>(); // LocaleData specific to this LocaleProviderAdapter. - private volatile LocaleData localeData; + private final StableValue localeData = StableValue.of(); /** * Returns the type of this LocaleProviderAdapter @@ -249,14 +249,7 @@ public LocaleResources getLocaleResources(Locale locale) { @Override public LocaleData getLocaleData() { - if (localeData == null) { - synchronized (this) { - if (localeData == null) { - localeData = new LocaleData(getAdapterType()); - } - } - } - return localeData; + return localeData.orElseSet(() -> new LocaleData(getAdapterType())); } @Override From c5f685f9aef4ab736eb200f47607ad0373bdee14 Mon Sep 17 00:00:00 2001 From: Shaojin Wen Date: Thu, 17 Jul 2025 01:30:53 +0800 Subject: [PATCH 05/10] CLDRLocaleProviderAdapter::AVAILABLE_LOCALES StableValue --- .../classes/sun/util/cldr/CLDRLocaleProviderAdapter.java | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/src/java.base/share/classes/sun/util/cldr/CLDRLocaleProviderAdapter.java b/src/java.base/share/classes/sun/util/cldr/CLDRLocaleProviderAdapter.java index 02a8ce29a0eb3..1d013e35852e7 100644 --- a/src/java.base/share/classes/sun/util/cldr/CLDRLocaleProviderAdapter.java +++ b/src/java.base/share/classes/sun/util/cldr/CLDRLocaleProviderAdapter.java @@ -60,7 +60,7 @@ public class CLDRLocaleProviderAdapter extends JRELocaleProviderAdapter { // cache to hold locale to locale mapping for language aliases. private static final Map langAliasesCache; // cache the available locales - private static volatile Locale[] AVAILABLE_LOCALES; + private static final StableValue AVAILABLE_LOCALES = StableValue.of(); static { parentLocalesMap = new ConcurrentHashMap<>(); @@ -123,12 +123,9 @@ public TimeZoneNameProvider getTimeZoneNameProvider() { @Override public Locale[] getAvailableLocales() { - if (AVAILABLE_LOCALES == null) { - AVAILABLE_LOCALES = createLanguageTagSet("AvailableLocales").stream() + return AVAILABLE_LOCALES.orElseSet(() -> createLanguageTagSet("AvailableLocales").stream() .map(Locale::forLanguageTag) - .toArray(Locale[]::new); - } - return AVAILABLE_LOCALES; + .toArray(Locale[]::new)); } private static Locale applyAliases(Locale loc) { From 051d15913e510820686aab2d9583d81bda086237 Mon Sep 17 00:00:00 2001 From: Shaojin Wen Date: Thu, 17 Jul 2025 12:11:07 +0800 Subject: [PATCH 06/10] use @Stable for startup performance --- .../util/cldr/CLDRLocaleProviderAdapter.java | 56 +++- .../FallbackLocaleProviderAdapter.java | 20 +- .../provider/JRELocaleProviderAdapter.java | 251 ++++++++++++++---- .../provider/LocaleProviderAdapter.java | 23 +- 4 files changed, 271 insertions(+), 79 deletions(-) diff --git a/src/java.base/share/classes/sun/util/cldr/CLDRLocaleProviderAdapter.java b/src/java.base/share/classes/sun/util/cldr/CLDRLocaleProviderAdapter.java index 1d013e35852e7..1aa40ea16facd 100644 --- a/src/java.base/share/classes/sun/util/cldr/CLDRLocaleProviderAdapter.java +++ b/src/java.base/share/classes/sun/util/cldr/CLDRLocaleProviderAdapter.java @@ -39,6 +39,7 @@ import java.util.spi.CalendarDataProvider; import java.util.spi.CalendarNameProvider; import java.util.spi.TimeZoneNameProvider; +import jdk.internal.vm.annotation.Stable; import sun.util.locale.provider.JRELocaleProviderAdapter; import sun.util.locale.provider.LocaleDataMetaInfo; import sun.util.locale.provider.LocaleProviderAdapter; @@ -60,7 +61,8 @@ public class CLDRLocaleProviderAdapter extends JRELocaleProviderAdapter { // cache to hold locale to locale mapping for language aliases. private static final Map langAliasesCache; // cache the available locales - private static final StableValue AVAILABLE_LOCALES = StableValue.of(); + @Stable + private static volatile Locale[] AVAILABLE_LOCALES; static { parentLocalesMap = new ConcurrentHashMap<>(); @@ -97,16 +99,34 @@ public BreakIteratorProvider getBreakIteratorProvider() { @Override public CalendarDataProvider getCalendarDataProvider() { - return calendarDataProvider.orElseSet(() -> new CLDRCalendarDataProviderImpl( - getAdapterType(), - getLanguageTagSet("CalendarData"))); + if (calendarDataProvider == null) { + CalendarDataProvider provider = new CLDRCalendarDataProviderImpl( + getAdapterType(), + getLanguageTagSet("CalendarData")); + + synchronized (this) { + if (calendarDataProvider == null) { + calendarDataProvider = provider; + } + } + } + return calendarDataProvider; } @Override public CalendarNameProvider getCalendarNameProvider() { - return calendarNameProvider.orElseSet(() -> new CLDRCalendarNameProviderImpl( - getAdapterType(), - getLanguageTagSet("FormatData"))); + if (calendarNameProvider == null) { + CalendarNameProvider provider = new CLDRCalendarNameProviderImpl( + getAdapterType(), + getLanguageTagSet("FormatData")); + + synchronized (this) { + if (calendarNameProvider == null) { + calendarNameProvider = provider; + } + } + } + return calendarNameProvider; } @Override @@ -116,16 +136,28 @@ public CollatorProvider getCollatorProvider() { @Override public TimeZoneNameProvider getTimeZoneNameProvider() { - return timeZoneNameProvider.orElseSet(() -> new CLDRTimeZoneNameProviderImpl( - getAdapterType(), - getLanguageTagSet("TimeZoneNames"))); + if (timeZoneNameProvider == null) { + TimeZoneNameProvider provider = new CLDRTimeZoneNameProviderImpl( + getAdapterType(), + getLanguageTagSet("TimeZoneNames")); + + synchronized (this) { + if (timeZoneNameProvider == null) { + timeZoneNameProvider = provider; + } + } + } + return timeZoneNameProvider; } @Override public Locale[] getAvailableLocales() { - return AVAILABLE_LOCALES.orElseSet(() -> createLanguageTagSet("AvailableLocales").stream() + if (AVAILABLE_LOCALES == null) { + AVAILABLE_LOCALES = createLanguageTagSet("AvailableLocales").stream() .map(Locale::forLanguageTag) - .toArray(Locale[]::new)); + .toArray(Locale[]::new); + } + return AVAILABLE_LOCALES; } private static Locale applyAliases(Locale loc) { diff --git a/src/java.base/share/classes/sun/util/locale/provider/FallbackLocaleProviderAdapter.java b/src/java.base/share/classes/sun/util/locale/provider/FallbackLocaleProviderAdapter.java index aaf0b4fe9a421..0d5bdcddec5d0 100644 --- a/src/java.base/share/classes/sun/util/locale/provider/FallbackLocaleProviderAdapter.java +++ b/src/java.base/share/classes/sun/util/locale/provider/FallbackLocaleProviderAdapter.java @@ -32,6 +32,8 @@ import java.util.Set; import java.util.stream.Stream; +import jdk.internal.vm.annotation.Stable; + /* * FallbackProviderAdapter implementation. Fallback provider serves the * following purposes: @@ -46,7 +48,8 @@ public class FallbackLocaleProviderAdapter extends JRELocaleProviderAdapter { private static final Locale[] AVAILABLE_LOCS = {Locale.US, Locale.ENGLISH, Locale.ROOT}; private static final Set AVAILABLE_LANGTAGS = Set.of("en-US", "en", "und"); - private final StableValue breakIteratorProvider = StableValue.of(); + @Stable + private volatile BreakIteratorProvider breakIteratorProvider; /** * Returns the type of this LocaleProviderAdapter @@ -82,8 +85,17 @@ public boolean isSupportedProviderLocale(Locale locale, Set langtags) { @Override // In order to correctly report supported locales public BreakIteratorProvider getBreakIteratorProvider() { - return breakIteratorProvider.orElseSet(() -> new BreakIteratorProviderImpl( - getAdapterType(), - getLanguageTagSet("BreakIteratorRules"))); + if (breakIteratorProvider == null) { + BreakIteratorProvider provider = new BreakIteratorProviderImpl( + getAdapterType(), + getLanguageTagSet("BreakIteratorRules")); + + synchronized (this) { + if (breakIteratorProvider == null) { + breakIteratorProvider = provider; + } + } + } + return breakIteratorProvider; } } diff --git a/src/java.base/share/classes/sun/util/locale/provider/JRELocaleProviderAdapter.java b/src/java.base/share/classes/sun/util/locale/provider/JRELocaleProviderAdapter.java index 5441d05d5888a..daa587f96cc98 100644 --- a/src/java.base/share/classes/sun/util/locale/provider/JRELocaleProviderAdapter.java +++ b/src/java.base/share/classes/sun/util/locale/provider/JRELocaleProviderAdapter.java @@ -46,6 +46,7 @@ import java.util.spi.LocaleNameProvider; import java.util.spi.LocaleServiceProvider; import java.util.spi.TimeZoneNameProvider; +import jdk.internal.vm.annotation.Stable; import sun.text.spi.JavaTimeDateTimePatternProvider; import sun.util.resources.LocaleData; import sun.util.spi.CalendarProvider; @@ -65,7 +66,8 @@ public class JRELocaleProviderAdapter extends LocaleProviderAdapter implements R = new ConcurrentHashMap<>(); // LocaleData specific to this LocaleProviderAdapter. - private final StableValue localeData = StableValue.of(); + @Stable + private volatile LocaleData localeData; /** * Returns the type of this LocaleProviderAdapter @@ -113,65 +115,132 @@ public

P getLocaleServiceProvider(Class

c) } } - private final StableValue breakIteratorProvider = StableValue.of(); - private final StableValue collatorProvider = StableValue.of(); - private final StableValue dateFormatProvider = StableValue.of(); - private final StableValue dateFormatSymbolsProvider = StableValue.of(); - private final StableValue decimalFormatSymbolsProvider = StableValue.of(); - private final StableValue numberFormatProvider = StableValue.of(); - - private final StableValue currencyNameProvider = StableValue.of(); - private final StableValue localeNameProvider = StableValue.of(); - protected final StableValue timeZoneNameProvider = StableValue.of(); - protected final StableValue calendarDataProvider = StableValue.of(); - protected final StableValue calendarNameProvider = StableValue.of(); - - private final StableValue calendarProvider = StableValue.of(); - private final StableValue javaTimeDateTimePatternProvider = StableValue.of(); + @Stable + private volatile BreakIteratorProvider breakIteratorProvider; + @Stable + private volatile CollatorProvider collatorProvider; + @Stable + private volatile DateFormatProvider dateFormatProvider; + @Stable + private volatile DateFormatSymbolsProvider dateFormatSymbolsProvider; + @Stable + private volatile DecimalFormatSymbolsProvider decimalFormatSymbolsProvider; + @Stable + private volatile NumberFormatProvider numberFormatProvider; + + @Stable + private volatile CurrencyNameProvider currencyNameProvider; + @Stable + private volatile LocaleNameProvider localeNameProvider; + @Stable + protected volatile TimeZoneNameProvider timeZoneNameProvider; + @Stable + protected volatile CalendarDataProvider calendarDataProvider; + @Stable + protected volatile CalendarNameProvider calendarNameProvider; + + @Stable + private volatile CalendarProvider calendarProvider; + @Stable + private volatile JavaTimeDateTimePatternProvider javaTimeDateTimePatternProvider; /* * Getter methods for java.text.spi.* providers */ @Override public BreakIteratorProvider getBreakIteratorProvider() { - return breakIteratorProvider.orElseSet(() -> new BreakIteratorProviderImpl( - getAdapterType(), - getLanguageTagSet("FormatData"))); + if (breakIteratorProvider == null) { + BreakIteratorProvider provider = new BreakIteratorProviderImpl( + getAdapterType(), + getLanguageTagSet("FormatData")); + + synchronized (this) { + if (breakIteratorProvider == null) { + breakIteratorProvider = provider; + } + } + } + return breakIteratorProvider; } @Override public CollatorProvider getCollatorProvider() { - return collatorProvider.orElseSet(() -> new CollatorProviderImpl( - getAdapterType(), - getLanguageTagSet("CollationData"))); + if (collatorProvider == null) { + CollatorProvider provider = new CollatorProviderImpl( + getAdapterType(), + getLanguageTagSet("CollationData")); + + synchronized (this) { + if (collatorProvider == null) { + collatorProvider = provider; + } + } + } + return collatorProvider; } @Override public DateFormatProvider getDateFormatProvider() { - return dateFormatProvider.orElseSet(() -> new DateFormatProviderImpl( - getAdapterType(), - getLanguageTagSet("FormatData"))); + if (dateFormatProvider == null) { + DateFormatProvider provider = new DateFormatProviderImpl( + getAdapterType(), + getLanguageTagSet("FormatData")); + + synchronized (this) { + if (dateFormatProvider == null) { + dateFormatProvider = provider; + } + } + } + return dateFormatProvider; } @Override public DateFormatSymbolsProvider getDateFormatSymbolsProvider() { - return dateFormatSymbolsProvider.orElseSet(() -> new DateFormatSymbolsProviderImpl( - getAdapterType(), - getLanguageTagSet("FormatData"))); + if (dateFormatSymbolsProvider == null) { + DateFormatSymbolsProvider provider = new DateFormatSymbolsProviderImpl( + getAdapterType(), + getLanguageTagSet("FormatData")); + + synchronized (this) { + if (dateFormatSymbolsProvider == null) { + dateFormatSymbolsProvider = provider; + } + } + } + return dateFormatSymbolsProvider; } @Override public DecimalFormatSymbolsProvider getDecimalFormatSymbolsProvider() { - return decimalFormatSymbolsProvider.orElseSet(() -> new DecimalFormatSymbolsProviderImpl( - getAdapterType(), - getLanguageTagSet("FormatData"))); + if (decimalFormatSymbolsProvider == null) { + DecimalFormatSymbolsProvider provider = new DecimalFormatSymbolsProviderImpl( + getAdapterType(), + getLanguageTagSet("FormatData")); + + synchronized (this) { + if (decimalFormatSymbolsProvider == null) { + decimalFormatSymbolsProvider = provider; + } + } + } + return decimalFormatSymbolsProvider; } @Override public NumberFormatProvider getNumberFormatProvider() { - return numberFormatProvider.orElseSet(() -> new NumberFormatProviderImpl( - getAdapterType(), - getLanguageTagSet("FormatData"))); + if (numberFormatProvider == null) { + NumberFormatProvider provider = new NumberFormatProviderImpl( + getAdapterType(), + getLanguageTagSet("FormatData")); + + synchronized (this) { + if (numberFormatProvider == null) { + numberFormatProvider = provider; + } + } + } + return numberFormatProvider; } /** @@ -179,37 +248,82 @@ public NumberFormatProvider getNumberFormatProvider() { */ @Override public CurrencyNameProvider getCurrencyNameProvider() { - return currencyNameProvider.orElseSet(() -> new CurrencyNameProviderImpl( - getAdapterType(), - getLanguageTagSet("CurrencyNames"))); + if (currencyNameProvider == null) { + CurrencyNameProvider provider = new CurrencyNameProviderImpl( + getAdapterType(), + getLanguageTagSet("CurrencyNames")); + + synchronized (this) { + if (currencyNameProvider == null) { + currencyNameProvider = provider; + } + } + } + return currencyNameProvider; } @Override public LocaleNameProvider getLocaleNameProvider() { - return localeNameProvider.orElseSet(() -> new LocaleNameProviderImpl( - getAdapterType(), - getLanguageTagSet("LocaleNames"))); + if (localeNameProvider == null) { + LocaleNameProvider provider = new LocaleNameProviderImpl( + getAdapterType(), + getLanguageTagSet("LocaleNames")); + + synchronized (this) { + if (localeNameProvider == null) { + localeNameProvider = provider; + } + } + } + return localeNameProvider; } @Override public TimeZoneNameProvider getTimeZoneNameProvider() { - return timeZoneNameProvider.orElseSet(() -> new TimeZoneNameProviderImpl( - getAdapterType(), - getLanguageTagSet("TimeZoneNames"))); + if (timeZoneNameProvider == null) { + TimeZoneNameProvider provider = new TimeZoneNameProviderImpl( + getAdapterType(), + getLanguageTagSet("TimeZoneNames")); + + synchronized (this) { + if (timeZoneNameProvider == null) { + timeZoneNameProvider = provider; + } + } + } + return timeZoneNameProvider; } @Override public CalendarDataProvider getCalendarDataProvider() { - return calendarDataProvider.orElseSet(() -> new CalendarDataProviderImpl( - getAdapterType(), - getLanguageTagSet("CalendarData"))); + if (calendarDataProvider == null) { + CalendarDataProvider provider = new CalendarDataProviderImpl( + getAdapterType(), + getLanguageTagSet("CalendarData")); + + synchronized (this) { + if (calendarDataProvider == null) { + calendarDataProvider = provider; + } + } + } + return calendarDataProvider; } @Override public CalendarNameProvider getCalendarNameProvider() { - return calendarNameProvider.orElseSet(() -> new CalendarNameProviderImpl( - getAdapterType(), - getLanguageTagSet("FormatData"))); + if (calendarNameProvider == null) { + CalendarNameProvider provider = new CalendarNameProviderImpl( + getAdapterType(), + getLanguageTagSet("FormatData")); + + synchronized (this) { + if (calendarNameProvider == null) { + calendarNameProvider = provider; + } + } + } + return calendarNameProvider; } /** @@ -217,9 +331,18 @@ public CalendarNameProvider getCalendarNameProvider() { */ @Override public CalendarProvider getCalendarProvider() { - return calendarProvider.orElseSet(() -> new CalendarProviderImpl( - getAdapterType(), - getLanguageTagSet("CalendarData"))); + if (calendarProvider == null) { + CalendarProvider provider = new CalendarProviderImpl( + getAdapterType(), + getLanguageTagSet("CalendarData")); + + synchronized (this) { + if (calendarProvider == null) { + calendarProvider = provider; + } + } + } + return calendarProvider; } /** @@ -227,9 +350,18 @@ public CalendarProvider getCalendarProvider() { */ @Override public JavaTimeDateTimePatternProvider getJavaTimeDateTimePatternProvider() { - return javaTimeDateTimePatternProvider.orElseSet(() -> new JavaTimeDateTimePatternImpl( - getAdapterType(), - getLanguageTagSet("FormatData"))); + if (javaTimeDateTimePatternProvider == null) { + JavaTimeDateTimePatternProvider provider = new JavaTimeDateTimePatternImpl( + getAdapterType(), + getLanguageTagSet("FormatData")); + + synchronized (this) { + if (javaTimeDateTimePatternProvider == null) { + javaTimeDateTimePatternProvider = provider; + } + } + } + return javaTimeDateTimePatternProvider; } @Override @@ -249,7 +381,14 @@ public LocaleResources getLocaleResources(Locale locale) { @Override public LocaleData getLocaleData() { - return localeData.orElseSet(() -> new LocaleData(getAdapterType())); + if (localeData == null) { + synchronized (this) { + if (localeData == null) { + localeData = new LocaleData(getAdapterType()); + } + } + } + return localeData; } @Override diff --git a/src/java.base/share/classes/sun/util/locale/provider/LocaleProviderAdapter.java b/src/java.base/share/classes/sun/util/locale/provider/LocaleProviderAdapter.java index 9d2ad0d4b7d8b..5d4d3a0a72d2f 100644 --- a/src/java.base/share/classes/sun/util/locale/provider/LocaleProviderAdapter.java +++ b/src/java.base/share/classes/sun/util/locale/provider/LocaleProviderAdapter.java @@ -48,6 +48,7 @@ import java.util.spi.LocaleNameProvider; import java.util.spi.LocaleServiceProvider; import java.util.spi.TimeZoneNameProvider; +import jdk.internal.vm.annotation.Stable; import sun.text.spi.JavaTimeDateTimePatternProvider; import sun.util.spi.CalendarProvider; @@ -73,7 +74,8 @@ public enum Type { private final String CLASSNAME; private final String UTIL_RESOURCES_PACKAGE; private final String TEXT_RESOURCES_PACKAGE; - private final StableValue adapter = StableValue.of(); + @Stable + private volatile LocaleProviderAdapter adapter; Type(String className) { this(className, null, null); @@ -98,11 +100,17 @@ public String getTextResourcesPackage() { } public LocaleProviderAdapter getAdapter() { - return adapter.orElseSet(() -> { - var type = Type.this; + if (adapter != null) { + return adapter; + } + return getAdapter0(); + } + + private synchronized LocaleProviderAdapter getAdapter0() { + if (adapter == null) { + // lazily load adapters here try { - // lazily load adapters here - return (LocaleProviderAdapter)Class.forName(type.getAdapterClassName()) + adapter = (LocaleProviderAdapter)Class.forName(getAdapterClassName()) .getDeclaredConstructor().newInstance(); } catch (NoSuchMethodException | InvocationTargetException | @@ -111,9 +119,10 @@ public LocaleProviderAdapter getAdapter() { InstantiationException | UnsupportedOperationException e) { throw new ServiceConfigurationError("Locale provider adapter \"" + - type + "\"cannot be instantiated.", e); + this + "\"cannot be instantiated.", e); } - }); + } + return adapter; } } From a1334d5c8b8eb942a823c3a7be61419fdb697f52 Mon Sep 17 00:00:00 2001 From: Shaojin Wen Date: Thu, 17 Jul 2025 13:10:46 +0800 Subject: [PATCH 07/10] simplify LocaleProviderAdapter$Type --- .../provider/LocaleProviderAdapter.java | 63 ++++++++++--------- 1 file changed, 35 insertions(+), 28 deletions(-) diff --git a/src/java.base/share/classes/sun/util/locale/provider/LocaleProviderAdapter.java b/src/java.base/share/classes/sun/util/locale/provider/LocaleProviderAdapter.java index 5d4d3a0a72d2f..6a0a9ef4cddce 100644 --- a/src/java.base/share/classes/sun/util/locale/provider/LocaleProviderAdapter.java +++ b/src/java.base/share/classes/sun/util/locale/provider/LocaleProviderAdapter.java @@ -65,32 +65,22 @@ public abstract class LocaleProviderAdapter { * Adapter type. */ public enum Type { - JRE("sun.util.locale.provider.JRELocaleProviderAdapter", "sun.util.resources", "sun.text.resources"), - CLDR("sun.util.cldr.CLDRLocaleProviderAdapter", "sun.util.resources.cldr", "sun.text.resources.cldr"), - SPI("sun.util.locale.provider.SPILocaleProviderAdapter"), - HOST("sun.util.locale.provider.HostLocaleProviderAdapter"), - FALLBACK("sun.util.locale.provider.FallbackLocaleProviderAdapter", "sun.util.resources", "sun.text.resources"); + JRE("sun.util.resources", "sun.text.resources"), + CLDR("sun.util.resources.cldr", "sun.text.resources.cldr"), + SPI(null, null), + HOST(null, null), + FALLBACK("sun.util.resources", "sun.text.resources"); - private final String CLASSNAME; private final String UTIL_RESOURCES_PACKAGE; private final String TEXT_RESOURCES_PACKAGE; @Stable private volatile LocaleProviderAdapter adapter; - Type(String className) { - this(className, null, null); - } - - Type(String className, String util, String text) { - CLASSNAME = className; + Type(String util, String text) { UTIL_RESOURCES_PACKAGE = util; TEXT_RESOURCES_PACKAGE = text; } - public String getAdapterClassName() { - return CLASSNAME; - } - public String getUtilResourcesPackage() { return UTIL_RESOURCES_PACKAGE; } @@ -109,21 +99,38 @@ public LocaleProviderAdapter getAdapter() { private synchronized LocaleProviderAdapter getAdapter0() { if (adapter == null) { // lazily load adapters here - try { - adapter = (LocaleProviderAdapter)Class.forName(getAdapterClassName()) - .getDeclaredConstructor().newInstance(); - } catch (NoSuchMethodException | - InvocationTargetException | - ClassNotFoundException | - IllegalAccessException | - InstantiationException | - UnsupportedOperationException e) { - throw new ServiceConfigurationError("Locale provider adapter \"" + - this + "\"cannot be instantiated.", e); - } + adapter = switch (this) { + case JRE -> createJREAdapter(); + case CLDR -> createCLDRAdapter(); + case SPI -> createSPIAdapter(); + case HOST -> createHOSTAdapter(); + case FALLBACK -> createFALLBACKAdapter(); + default -> throw new ServiceConfigurationError("Locale provider adapter \"" + + this + "\"cannot be instantiated."); + }; } return adapter; } + + private static LocaleProviderAdapter createJREAdapter() { + return new JRELocaleProviderAdapter(); + } + + private static LocaleProviderAdapter createCLDRAdapter() { + return new sun.util.cldr.CLDRLocaleProviderAdapter(); + } + + private static LocaleProviderAdapter createSPIAdapter() { + return new SPILocaleProviderAdapter(); + } + + private static LocaleProviderAdapter createHOSTAdapter() { + return new HostLocaleProviderAdapter(); + } + + private static LocaleProviderAdapter createFALLBACKAdapter() { + return new FallbackLocaleProviderAdapter(); + } } /** From a839b81730596c2592481530f3ff15cafc32dee1 Mon Sep 17 00:00:00 2001 From: Shaojin Wen Date: Thu, 17 Jul 2025 16:37:07 +0800 Subject: [PATCH 08/10] add benchmark --- .../bench/java/text/NumberFormatBench.java | 41 +++++++++++++++++++ 1 file changed, 41 insertions(+) create mode 100644 test/micro/org/openjdk/bench/java/text/NumberFormatBench.java diff --git a/test/micro/org/openjdk/bench/java/text/NumberFormatBench.java b/test/micro/org/openjdk/bench/java/text/NumberFormatBench.java new file mode 100644 index 0000000000000..99f87054efada --- /dev/null +++ b/test/micro/org/openjdk/bench/java/text/NumberFormatBench.java @@ -0,0 +1,41 @@ +/* + * Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package org.openjdk.bench.java.text; + +import java.util.concurrent.TimeUnit; + +import org.openjdk.jmh.annotations.*; + +import java.text.NumberFormat; +import java.util.Locale; + +@BenchmarkMode(Mode.Throughput) +@OutputTimeUnit(TimeUnit.MICROSECONDS) +@State(Scope.Thread) +public class NumberFormatBench { + + @Benchmark + public void getInstance() { + NumberFormat.getInstance(Locale.ENGLISH); + } +} From 94d0dea3ee31a133005d1859b112903a2ceee049 Mon Sep 17 00:00:00 2001 From: Shaojin Wen Date: Thu, 17 Jul 2025 16:37:26 +0800 Subject: [PATCH 09/10] reduce codeSize --- .../provider/JRELocaleProviderAdapter.java | 44 +++++---------- .../provider/LocaleProviderAdapter.java | 54 ++++++++++++++----- 2 files changed, 56 insertions(+), 42 deletions(-) diff --git a/src/java.base/share/classes/sun/util/locale/provider/JRELocaleProviderAdapter.java b/src/java.base/share/classes/sun/util/locale/provider/JRELocaleProviderAdapter.java index daa587f96cc98..d78e352b04479 100644 --- a/src/java.base/share/classes/sun/util/locale/provider/JRELocaleProviderAdapter.java +++ b/src/java.base/share/classes/sun/util/locale/provider/JRELocaleProviderAdapter.java @@ -83,36 +83,20 @@ public LocaleProviderAdapter.Type getAdapterType() { @Override @SuppressWarnings("unchecked") public

P getLocaleServiceProvider(Class

c) { - switch (c.getSimpleName()) { - case "BreakIteratorProvider": - return (P) getBreakIteratorProvider(); - case "CollatorProvider": - return (P) getCollatorProvider(); - case "DateFormatProvider": - return (P) getDateFormatProvider(); - case "DateFormatSymbolsProvider": - return (P) getDateFormatSymbolsProvider(); - case "DecimalFormatSymbolsProvider": - return (P) getDecimalFormatSymbolsProvider(); - case "NumberFormatProvider": - return (P) getNumberFormatProvider(); - case "CurrencyNameProvider": - return (P) getCurrencyNameProvider(); - case "LocaleNameProvider": - return (P) getLocaleNameProvider(); - case "TimeZoneNameProvider": - return (P) getTimeZoneNameProvider(); - case "CalendarDataProvider": - return (P) getCalendarDataProvider(); - case "CalendarNameProvider": - return (P) getCalendarNameProvider(); - case "CalendarProvider": - return (P) getCalendarProvider(); - case "JavaTimeDateTimePatternProvider": - return (P) getJavaTimeDateTimePatternProvider(); - default: - throw new InternalError("should not come down here"); - } + if (c == BreakIteratorProvider.class) return (P) getBreakIteratorProvider(); + if (c == CollatorProvider.class) return (P) getCollatorProvider(); + if (c == DateFormatProvider.class) return (P) getDateFormatProvider(); + if (c == DateFormatSymbolsProvider.class) return (P) getDateFormatSymbolsProvider(); + if (c == DecimalFormatSymbolsProvider.class) return (P) getDecimalFormatSymbolsProvider(); + if (c == NumberFormatProvider.class) return (P) getNumberFormatProvider(); + if (c == CurrencyNameProvider.class) return (P) getCurrencyNameProvider(); + if (c == LocaleNameProvider.class) return (P) getLocaleNameProvider(); + if (c == TimeZoneNameProvider.class) return (P) getTimeZoneNameProvider(); + if (c == CalendarDataProvider.class) return (P) getCalendarDataProvider(); + if (c == CalendarNameProvider.class) return (P) getCalendarNameProvider(); + if (c == CalendarProvider.class) return (P) getCalendarProvider(); + if (c == JavaTimeDateTimePatternProvider.class) return (P) getJavaTimeDateTimePatternProvider(); + throw new InternalError("should not come down here"); } @Stable diff --git a/src/java.base/share/classes/sun/util/locale/provider/LocaleProviderAdapter.java b/src/java.base/share/classes/sun/util/locale/provider/LocaleProviderAdapter.java index 6a0a9ef4cddce..730a025a513d5 100644 --- a/src/java.base/share/classes/sun/util/locale/provider/LocaleProviderAdapter.java +++ b/src/java.base/share/classes/sun/util/locale/provider/LocaleProviderAdapter.java @@ -141,8 +141,20 @@ private static LocaleProviderAdapter createFALLBACKAdapter() { /** * Adapter lookup cache. */ - private static final ConcurrentMap, ConcurrentMap> - adapterCache = new ConcurrentHashMap<>(); + private static final ConcurrentMap + breakIteratorProviderAdapterMap = new ConcurrentHashMap<>(), + collatorProviderAdapterMap = new ConcurrentHashMap<>(), + dateFormatProviderAdapterMap = new ConcurrentHashMap<>(), + dateFormatSymbolsProviderAdapterMap = new ConcurrentHashMap<>(), + decimalFormatSymbolsProviderAdapterMap = new ConcurrentHashMap<>(), + numberFormatProviderAdapterMap = new ConcurrentHashMap<>(), + currencyNameProviderAdapterMap = new ConcurrentHashMap<>(), + localeNameProviderAdapterMap = new ConcurrentHashMap<>(), + timeZoneNameProviderAdapterMap = new ConcurrentHashMap<>(), + calendarDataProviderAdapterMap = new ConcurrentHashMap<>(), + calendarNameProviderAdapterMap = new ConcurrentHashMap<>(), + calendarProviderAdapterMap = new ConcurrentHashMap<>(), + javaTimeDateTimePatternProviderAdapterMap = new ConcurrentHashMap<>(); static { String order = System.getProperty("java.locale.providers"); @@ -222,6 +234,24 @@ public static List getAdapterPreference() { return adapterPreference; } + @SuppressWarnings("unchecked") + private static ConcurrentMap getAdapterMap(Class providerClass) { + if (providerClass == BreakIteratorProvider.class) return breakIteratorProviderAdapterMap; + if (providerClass == CollatorProvider.class) return collatorProviderAdapterMap; + if (providerClass == DateFormatProvider.class) return dateFormatProviderAdapterMap; + if (providerClass == DateFormatSymbolsProvider.class) return dateFormatSymbolsProviderAdapterMap; + if (providerClass == DecimalFormatSymbolsProvider.class) return decimalFormatSymbolsProviderAdapterMap; + if (providerClass == NumberFormatProvider.class) return numberFormatProviderAdapterMap; + if (providerClass == CurrencyNameProvider.class) return currencyNameProviderAdapterMap; + if (providerClass == LocaleNameProvider.class) return localeNameProviderAdapterMap; + if (providerClass == TimeZoneNameProvider.class) return timeZoneNameProviderAdapterMap; + if (providerClass == CalendarDataProvider.class) return calendarDataProviderAdapterMap; + if (providerClass == CalendarNameProvider.class) return calendarNameProviderAdapterMap; + if (providerClass == CalendarProvider.class) return calendarProviderAdapterMap; + if (providerClass == JavaTimeDateTimePatternProvider.class) return javaTimeDateTimePatternProviderAdapterMap; + throw new InternalError("should not come down here"); + } + /** * Returns a LocaleProviderAdapter for the given locale service provider that * best matches the given locale. This method returns the LocaleProviderAdapter @@ -236,23 +266,23 @@ public static LocaleProviderAdapter getAdapter(Class adapterMap = adapterCache.get(providerClass); - if (adapterMap != null) { - if ((adapter = adapterMap.get(locale)) != null) { - return adapter; - } - } else { - adapterMap = new ConcurrentHashMap<>(); - adapterCache.putIfAbsent(providerClass, adapterMap); + ConcurrentMap adapterMap = getAdapterMap(providerClass); + if ((adapter = adapterMap.get(locale)) != null) { + return adapter; } + return getAdapter0(providerClass, locale, adapterMap); + } + + private static LocaleProviderAdapter getAdapter0(Class providerClass, + Locale locale, + ConcurrentMap adapterMap) { // Fast look-up for the given locale - adapter = findAdapter(providerClass, locale); + LocaleProviderAdapter adapter = findAdapter(providerClass, locale); if (adapter != null) { adapterMap.putIfAbsent(locale, adapter); return adapter; } - // Try finding an adapter in the normal candidate locales path of the given locale. List lookupLocales = ResourceBundle.Control.getControl(ResourceBundle.Control.FORMAT_DEFAULT) .getCandidateLocales("", locale); From 4333aa713fc6739d6ec759a3cd691fb610e899c9 Mon Sep 17 00:00:00 2001 From: Shaojin Wen Date: Sun, 20 Jul 2025 11:19:54 +0800 Subject: [PATCH 10/10] simplify getAdapter0 --- .../provider/LocaleProviderAdapter.java | 30 ++++--------------- 1 file changed, 5 insertions(+), 25 deletions(-) diff --git a/src/java.base/share/classes/sun/util/locale/provider/LocaleProviderAdapter.java b/src/java.base/share/classes/sun/util/locale/provider/LocaleProviderAdapter.java index 730a025a513d5..820e80342df7d 100644 --- a/src/java.base/share/classes/sun/util/locale/provider/LocaleProviderAdapter.java +++ b/src/java.base/share/classes/sun/util/locale/provider/LocaleProviderAdapter.java @@ -100,37 +100,17 @@ private synchronized LocaleProviderAdapter getAdapter0() { if (adapter == null) { // lazily load adapters here adapter = switch (this) { - case JRE -> createJREAdapter(); - case CLDR -> createCLDRAdapter(); - case SPI -> createSPIAdapter(); - case HOST -> createHOSTAdapter(); - case FALLBACK -> createFALLBACKAdapter(); + case JRE -> new JRELocaleProviderAdapter(); + case CLDR -> new sun.util.cldr.CLDRLocaleProviderAdapter(); + case SPI -> new SPILocaleProviderAdapter(); + case HOST -> new HostLocaleProviderAdapter(); + case FALLBACK -> new FallbackLocaleProviderAdapter(); default -> throw new ServiceConfigurationError("Locale provider adapter \"" + this + "\"cannot be instantiated."); }; } return adapter; } - - private static LocaleProviderAdapter createJREAdapter() { - return new JRELocaleProviderAdapter(); - } - - private static LocaleProviderAdapter createCLDRAdapter() { - return new sun.util.cldr.CLDRLocaleProviderAdapter(); - } - - private static LocaleProviderAdapter createSPIAdapter() { - return new SPILocaleProviderAdapter(); - } - - private static LocaleProviderAdapter createHOSTAdapter() { - return new HostLocaleProviderAdapter(); - } - - private static LocaleProviderAdapter createFALLBACKAdapter() { - return new FallbackLocaleProviderAdapter(); - } } /**