Skip to content

Commit d9af4d6

Browse files
imasahirojhoeller
authored andcommitted
ResourceBundleMessageSource uses ConcurrentHashMaps instead of synchronization
Issue: https://jira.spring.io/browse/SPR-16235
1 parent f72318a commit d9af4d6

File tree

1 file changed

+52
-46
lines changed

1 file changed

+52
-46
lines changed

spring-context/src/main/java/org/springframework/context/support/ResourceBundleMessageSource.java

Lines changed: 52 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@
3333
import java.util.PropertyResourceBundle;
3434
import java.util.ResourceBundle;
3535
import java.util.Set;
36+
import java.util.concurrent.ConcurrentHashMap;
3637

3738
import org.springframework.beans.factory.BeanClassLoaderAware;
3839
import org.springframework.lang.Nullable;
@@ -80,7 +81,7 @@ public class ResourceBundleMessageSource extends AbstractResourceBasedMessageSou
8081
* This allows for very efficient hash lookups, significantly faster
8182
* than the ResourceBundle class's own cache.
8283
*/
83-
private final Map<String, Map<Locale, ResourceBundle>> cachedResourceBundles = new HashMap<>();
84+
private final Map<String, Map<Locale, ResourceBundle>> cachedResourceBundles = new ConcurrentHashMap<>();
8485

8586
/**
8687
* Cache to hold already generated MessageFormats.
@@ -90,7 +91,7 @@ public class ResourceBundleMessageSource extends AbstractResourceBasedMessageSou
9091
* very efficient hash lookups without concatenated keys.
9192
* @see #getMessageFormat
9293
*/
93-
private final Map<ResourceBundle, Map<String, Map<Locale, MessageFormat>>> cachedBundleMessageFormats = new HashMap<>();
94+
private final Map<ResourceBundle, Map<String, Map<Locale, MessageFormat>>> cachedBundleMessageFormats = new ConcurrentHashMap<>();
9495

9596

9697
/**
@@ -178,31 +179,32 @@ protected ResourceBundle getResourceBundle(String basename, Locale locale) {
178179
}
179180
else {
180181
// Cache forever: prefer locale cache over repeated getBundle calls.
181-
synchronized (this.cachedResourceBundles) {
182-
Map<Locale, ResourceBundle> localeMap = this.cachedResourceBundles.get(basename);
183-
if (localeMap != null) {
184-
ResourceBundle bundle = localeMap.get(locale);
185-
if (bundle != null) {
186-
return bundle;
187-
}
188-
}
189-
try {
190-
ResourceBundle bundle = doGetBundle(basename, locale);
191-
if (localeMap == null) {
192-
localeMap = new HashMap<>();
193-
this.cachedResourceBundles.put(basename, localeMap);
194-
}
195-
localeMap.put(locale, bundle);
182+
Map<Locale, ResourceBundle> localeMap = this.cachedResourceBundles.get(basename);
183+
if (localeMap != null) {
184+
ResourceBundle bundle = localeMap.get(locale);
185+
if (bundle != null) {
196186
return bundle;
197187
}
198-
catch (MissingResourceException ex) {
199-
if (logger.isWarnEnabled()) {
200-
logger.warn("ResourceBundle [" + basename + "] not found for MessageSource: " + ex.getMessage());
188+
}
189+
try {
190+
ResourceBundle bundle = doGetBundle(basename, locale);
191+
if (localeMap == null) {
192+
localeMap = new ConcurrentHashMap<>();
193+
Map<Locale, ResourceBundle> existing = this.cachedResourceBundles.putIfAbsent(basename, localeMap);
194+
if (existing != null) {
195+
localeMap = existing;
201196
}
202-
// Assume bundle not found
203-
// -> do NOT throw the exception to allow for checking parent message source.
204-
return null;
205197
}
198+
localeMap.put(locale, bundle);
199+
return bundle;
200+
}
201+
catch (MissingResourceException ex) {
202+
if (logger.isWarnEnabled()) {
203+
logger.warn("ResourceBundle [" + basename + "] not found for MessageSource: " + ex.getMessage());
204+
}
205+
// Assume bundle not found
206+
// -> do NOT throw the exception to allow for checking parent message source.
207+
return null;
206208
}
207209
}
208210
}
@@ -249,36 +251,40 @@ protected ResourceBundle loadBundle(Reader reader) throws IOException {
249251
protected MessageFormat getMessageFormat(ResourceBundle bundle, String code, Locale locale)
250252
throws MissingResourceException {
251253

252-
synchronized (this.cachedBundleMessageFormats) {
253-
Map<String, Map<Locale, MessageFormat>> codeMap = this.cachedBundleMessageFormats.get(bundle);
254-
Map<Locale, MessageFormat> localeMap = null;
255-
if (codeMap != null) {
256-
localeMap = codeMap.get(code);
257-
if (localeMap != null) {
258-
MessageFormat result = localeMap.get(locale);
259-
if (result != null) {
260-
return result;
261-
}
254+
Map<String, Map<Locale, MessageFormat>> codeMap = this.cachedBundleMessageFormats.get(bundle);
255+
Map<Locale, MessageFormat> localeMap = null;
256+
if (codeMap != null) {
257+
localeMap = codeMap.get(code);
258+
if (localeMap != null) {
259+
MessageFormat result = localeMap.get(locale);
260+
if (result != null) {
261+
return result;
262262
}
263263
}
264+
}
264265

265-
String msg = getStringOrNull(bundle, code);
266-
if (msg != null) {
267-
if (codeMap == null) {
268-
codeMap = new HashMap<>();
269-
this.cachedBundleMessageFormats.put(bundle, codeMap);
266+
String msg = getStringOrNull(bundle, code);
267+
if (msg != null) {
268+
if (codeMap == null) {
269+
codeMap = new ConcurrentHashMap<>();
270+
Map<String, Map<Locale, MessageFormat>> existing = this.cachedBundleMessageFormats.putIfAbsent(bundle, codeMap);
271+
if (existing != null) {
272+
codeMap = existing;
270273
}
271-
if (localeMap == null) {
272-
localeMap = new HashMap<>();
273-
codeMap.put(code, localeMap);
274+
}
275+
if (localeMap == null) {
276+
localeMap = new ConcurrentHashMap<>();
277+
Map<Locale, MessageFormat> existing = codeMap.putIfAbsent(code, localeMap);
278+
if (existing != null) {
279+
localeMap = existing;
274280
}
275-
MessageFormat result = createMessageFormat(msg, locale);
276-
localeMap.put(locale, result);
277-
return result;
278281
}
279-
280-
return null;
282+
MessageFormat result = createMessageFormat(msg, locale);
283+
localeMap.put(locale, result);
284+
return result;
281285
}
286+
287+
return null;
282288
}
283289

284290
/**

0 commit comments

Comments
 (0)