Author: scolebourne Date: Fri Mar 4 14:59:22 2011 New Revision: 1077984 URL: http://svn.apache.org/viewvc?rev=1077984&view=rev Log: Use concurrent instead of synchronization; Javadoc
Modified: commons/proper/lang/trunk/src/main/java/org/apache/commons/lang3/LocaleUtils.java Modified: commons/proper/lang/trunk/src/main/java/org/apache/commons/lang3/LocaleUtils.java URL: http://svn.apache.org/viewvc/commons/proper/lang/trunk/src/main/java/org/apache/commons/lang3/LocaleUtils.java?rev=1077984&r1=1077983&r2=1077984&view=diff ============================================================================== --- commons/proper/lang/trunk/src/main/java/org/apache/commons/lang3/LocaleUtils.java (original) +++ commons/proper/lang/trunk/src/main/java/org/apache/commons/lang3/LocaleUtils.java Fri Mar 4 14:59:22 2011 @@ -19,12 +19,12 @@ package org.apache.commons.lang3; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; -import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Locale; -import java.util.Map; import java.util.Set; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ConcurrentMap; /** * <p>Operations to assist when working with a {@link Locale}.</p> @@ -39,21 +39,13 @@ import java.util.Set; */ public class LocaleUtils { - /** Unmodifiable list of available locales. */ - //@GuardedBy("this") - private static List<Locale> cAvailableLocaleList; // lazily created by availableLocaleList() - - /** Unmodifiable set of available locales. */ - //@GuardedBy("this") - private static Set<Locale> cAvailableLocaleSet; // lazily created by availableLocaleSet() - - /** Unmodifiable map of language locales by country. */ - private static final Map<String, List<Locale>> cLanguagesByCountry = - Collections.synchronizedMap(new HashMap<String, List<Locale>>()); - - /** Unmodifiable map of country locales by language. */ - private static final Map<String, List<Locale>> cCountriesByLanguage = - Collections.synchronizedMap(new HashMap<String, List<Locale>>()); + /** Concurrent map of language locales by country. */ + private static final ConcurrentMap<String, List<Locale>> cLanguagesByCountry = + new ConcurrentHashMap<String, List<Locale>>(); + + /** Concurrent map of country locales by language. */ + private static final ConcurrentMap<String, List<Locale>> cCountriesByLanguage = + new ConcurrentHashMap<String, List<Locale>>(); /** * <p><code>LocaleUtils</code> instances should NOT be constructed in standard programming. @@ -143,7 +135,7 @@ public class LocaleUtils { * </pre> * * @param locale the locale to start from - * @return the unmodifiable list of Locale objects, 0 being locale, never null + * @return the unmodifiable list of Locale objects, 0 being locale, not null */ public static List<Locale> localeLookupList(Locale locale) { return localeLookupList(locale, locale); @@ -165,7 +157,7 @@ public class LocaleUtils { * * @param locale the locale to start from, null returns empty list * @param defaultLocale the default locale to use if no other is found - * @return the unmodifiable list of Locale objects, 0 being locale, never null + * @return the unmodifiable list of Locale objects, 0 being locale, not null */ public static List<Locale> localeLookupList(Locale locale, Locale defaultLocale) { List<Locale> list = new ArrayList<Locale>(4); @@ -195,22 +187,7 @@ public class LocaleUtils { * @return the unmodifiable list of available locales */ public static List<Locale> availableLocaleList() { - if(cAvailableLocaleList == null) { - initAvailableLocaleList(); - } - return cAvailableLocaleList; - } - - /** - * Initializes the availableLocaleList. It is separate from availableLocaleList() - * to avoid the synchronized block affecting normal use, yet synchronized and - * lazy loading to avoid a static block affecting other methods in this class. - */ - private static synchronized void initAvailableLocaleList() { - if(cAvailableLocaleList == null) { - List<Locale> list = Arrays.asList(Locale.getAvailableLocales()); - cAvailableLocaleList = Collections.unmodifiableList(list); - } + return SyncAvoid.AVAILABLE_LOCALE_LIST; } //----------------------------------------------------------------------- @@ -224,21 +201,7 @@ public class LocaleUtils { * @return the unmodifiable set of available locales */ public static Set<Locale> availableLocaleSet() { - if(cAvailableLocaleSet == null) { - initAvailableLocaleSet(); - } - return cAvailableLocaleSet; - } - - /** - * Initializes the availableLocaleSet. It is separate from availableLocaleSet() - * to avoid the synchronized block affecting normal use, yet synchronized and - * lazy loading to avoid a static block affecting other methods in this class. - */ - private static synchronized void initAvailableLocaleSet() { - if(cAvailableLocaleSet == null) { - cAvailableLocaleSet = Collections.unmodifiableSet( new HashSet<Locale>(availableLocaleList()) ); - } + return SyncAvoid.AVAILABLE_LOCALE_SET; } //----------------------------------------------------------------------- @@ -260,26 +223,26 @@ public class LocaleUtils { * languages available for that country. Variant locales are removed.</p> * * @param countryCode the 2 letter country code, null returns empty - * @return an unmodifiable List of Locale objects, never null + * @return an unmodifiable List of Locale objects, not null */ public static List<Locale> languagesByCountry(String countryCode) { - List<Locale> langs = cLanguagesByCountry.get(countryCode); //syncd + if (countryCode == null) { + return Collections.emptyList(); + } + List<Locale> langs = cLanguagesByCountry.get(countryCode); if (langs == null) { - if (countryCode != null) { - langs = new ArrayList<Locale>(); - List<Locale> locales = availableLocaleList(); - for (int i = 0; i < locales.size(); i++) { - Locale locale = locales.get(i); - if (countryCode.equals(locale.getCountry()) && - locale.getVariant().length() == 0) { - langs.add(locale); - } + langs = new ArrayList<Locale>(); + List<Locale> locales = availableLocaleList(); + for (int i = 0; i < locales.size(); i++) { + Locale locale = locales.get(i); + if (countryCode.equals(locale.getCountry()) && + locale.getVariant().length() == 0) { + langs.add(locale); } - langs = Collections.unmodifiableList(langs); - } else { - langs = Collections.emptyList(); } - cLanguagesByCountry.put(countryCode, langs); //syncd + langs = Collections.unmodifiableList(langs); + cLanguagesByCountry.putIfAbsent(countryCode, langs); + langs = cLanguagesByCountry.get(countryCode); } return langs; } @@ -292,29 +255,44 @@ public class LocaleUtils { * countries available for that language. Variant locales are removed.</p> * * @param languageCode the 2 letter language code, null returns empty - * @return an unmodifiable List of Locale objects, never null + * @return an unmodifiable List of Locale objects, not null */ public static List<Locale> countriesByLanguage(String languageCode) { - List<Locale> countries = cCountriesByLanguage.get(languageCode); //syncd + if (languageCode == null) { + return Collections.emptyList(); + } + List<Locale> countries = cCountriesByLanguage.get(languageCode); if (countries == null) { - if (languageCode != null) { - countries = new ArrayList<Locale>(); - List<Locale> locales = availableLocaleList(); - for (int i = 0; i < locales.size(); i++) { - Locale locale = locales.get(i); - if (languageCode.equals(locale.getLanguage()) && - locale.getCountry().length() != 0 && - locale.getVariant().length() == 0) { - countries.add(locale); - } + countries = new ArrayList<Locale>(); + List<Locale> locales = availableLocaleList(); + for (int i = 0; i < locales.size(); i++) { + Locale locale = locales.get(i); + if (languageCode.equals(locale.getLanguage()) && + locale.getCountry().length() != 0 && + locale.getVariant().length() == 0) { + countries.add(locale); } - countries = Collections.unmodifiableList(countries); - } else { - countries = Collections.emptyList(); } - cCountriesByLanguage.put(languageCode, countries); //syncd + countries = Collections.unmodifiableList(countries); + cCountriesByLanguage.putIfAbsent(languageCode, countries); + countries = cCountriesByLanguage.get(languageCode); } return countries; } + //----------------------------------------------------------------------- + // class to avoid synchronization + static class SyncAvoid { + /** Unmodifiable list of available locales. */ + private static List<Locale> AVAILABLE_LOCALE_LIST; + /** Unmodifiable set of available locales. */ + private static Set<Locale> AVAILABLE_LOCALE_SET; + + static { + List<Locale> list = new ArrayList<Locale>(Arrays.asList(Locale.getAvailableLocales())); // extra safe + AVAILABLE_LOCALE_LIST = Collections.unmodifiableList(list); + AVAILABLE_LOCALE_SET = Collections.unmodifiableSet(new HashSet<Locale>(availableLocaleList())); + } + } + }