I am writing a utility class which uses map as a cache store. Now since its going to be used in multithreaded environment. I came up with usage of either synchronized hashmap while doing put operation or ConcurrentHashMap( using putIfAbsent) which I am still confused about if it is prone to override of key-value(though key-value is unique in my case) and both have there pros and cons. So I am not able to decide. There might be some other cache store which i can use for this purpose, do suggest but I am more interested in knowing which is to be used CHM or Hashmap if this is the only option.
In Comments of program is CHM usage which I thought else I have used HashMap.
public final class DateTime {
private static final Map<CountryLanguage, Locale> localeMap = new HashMap<>();
/*private static final Map<CountryLanguage, Locale> localeMap = new ConcurrentHashMap<>();*/
public static String getDateTime1(String pattern, LocalDateTime localDateTime, String language,
String country) {
if (language == null || language.isEmpty()) {
throw new NullPointerException("Language cannot be null or empty");
}
CountryLanguage countryLanguage = new CountryLanguage(language, country);
if (!localeMap.containsKey(countryLanguage)) {
synchronized (localeMap) {
// Putting double lock
if (!localeMap.containsKey(countryLanguage)) {
for (Locale locale : Locale.getAvailableLocales()) {
if (locale.getLanguage().equals(language) && locale.getCountry().equals(country)) {
localeMap.put(new CountryLanguage(language, country), locale);
}
}
}
}
}
/*for (Locale locale : Locale.getAvailableLocales()) {
if (locale.getLanguage().equals(language) && locale.getCountry().equals(country)) {
localeMap.putIfAbsent(new CountryLanguage(language, country), locale);
}
}*/
Locale locale = localeMap.get(countryLanguage);
if (locale == null) {
locale = Locale.ROOT;
}
DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern(pattern, locale);
return localDateTime.format(dateTimeFormatter);
}
NOTE:
- I have an inner class CountryLanguage which has String country,String language as member variable and both hashCode and equals methods have been overridden.
Edit1: I am not making whole map as synchronized I am just using synchronized on map while put operation. And I am using double check to make sure no two key-value exists
CountryLanguage
. You'll have more issues when you remove elements, but so far you don't. If you need a reliable cache better look at existing solutions, e.g. Guava. – Marvinnew Locale(countryLanguage.getLanguage(), countryLanguage.getCountry())
every time you need the locale corresponding to a CountryLanguage. Creating a Locale is fast, and already uses a cache internally. – JB Nizet