Consistent fine-tuning of synchronized and concurrent data structures

In particular, avoiding synchronized Sets and Maps wherever possible (preferring a ConcurrentHashMap even instead of a synchronized Set) and specifying appropriate ConcurrentHashMap initial capacities (even if we end up choosing 16).
This commit is contained in:
Juergen Hoeller
2012-12-12 23:46:26 +01:00
parent a2f8902b3a
commit b9df7d68d9
58 changed files with 380 additions and 387 deletions

View File

@@ -56,7 +56,7 @@ public class ConcurrentMapCache implements Cache {
* @param name the name of the cache
*/
public ConcurrentMapCache(String name) {
this(name, new ConcurrentHashMap<Object, Object>(), true);
this(name, new ConcurrentHashMap<Object, Object>(256), true);
}
/**
@@ -65,7 +65,7 @@ public class ConcurrentMapCache implements Cache {
* @param allowNullValues whether to accept and convert null values for this cache
*/
public ConcurrentMapCache(String name, boolean allowNullValues) {
this(name, new ConcurrentHashMap<Object, Object>(), allowNullValues);
this(name, new ConcurrentHashMap<Object, Object>(256), allowNullValues);
}
/**

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2002-2011 the original author or authors.
* Copyright 2002-2012 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -36,7 +36,7 @@ import org.springframework.cache.CacheManager;
*/
public class ConcurrentMapCacheManager implements CacheManager {
private final ConcurrentMap<String, Cache> cacheMap = new ConcurrentHashMap<String, Cache>();
private final ConcurrentMap<String, Cache> cacheMap = new ConcurrentHashMap<String, Cache>(16);
private boolean dynamic = true;

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2002-2011 the original author or authors.
* Copyright 2002-2012 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -25,6 +25,7 @@ import java.util.concurrent.ConcurrentHashMap;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.core.BridgeMethodResolver;
import org.springframework.util.ClassUtils;
import org.springframework.util.ObjectUtils;
@@ -48,6 +49,7 @@ import org.springframework.util.ObjectUtils;
* configurable.
*
* @author Costin Leau
* @author Juergen Hoeller
* @since 3.1
*/
public abstract class AbstractFallbackCacheOperationSource implements CacheOperationSource {
@@ -70,7 +72,8 @@ public abstract class AbstractFallbackCacheOperationSource implements CacheOpera
* <p>As this base class is not marked Serializable, the cache will be recreated
* after serialization - provided that the concrete subclass is Serializable.
*/
final Map<Object, Collection<CacheOperation>> attributeCache = new ConcurrentHashMap<Object, Collection<CacheOperation>>();
final Map<Object, Collection<CacheOperation>> attributeCache =
new ConcurrentHashMap<Object, Collection<CacheOperation>>(1024);
/**

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2002-2011 the original author or authors.
* Copyright 2002-2012 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -39,16 +39,16 @@ import org.springframework.expression.spel.standard.SpelExpressionParser;
*/
class ExpressionEvaluator {
private SpelExpressionParser parser = new SpelExpressionParser();
private final SpelExpressionParser parser = new SpelExpressionParser();
// shared param discoverer since it caches data internally
private ParameterNameDiscoverer paramNameDiscoverer = new LocalVariableTableParameterNameDiscoverer();
private final ParameterNameDiscoverer paramNameDiscoverer = new LocalVariableTableParameterNameDiscoverer();
private Map<String, Expression> conditionCache = new ConcurrentHashMap<String, Expression>();
private final Map<String, Expression> conditionCache = new ConcurrentHashMap<String, Expression>(64);
private Map<String, Expression> keyCache = new ConcurrentHashMap<String, Expression>();
private final Map<String, Expression> keyCache = new ConcurrentHashMap<String, Expression>(64);
private Map<String, Method> targetMethodCache = new ConcurrentHashMap<String, Method>();
private final Map<String, Method> targetMethodCache = new ConcurrentHashMap<String, Method>(64);
public EvaluationContext createEvaluationContext(

View File

@@ -29,9 +29,8 @@ import org.springframework.cache.CacheManager;
import org.springframework.util.Assert;
/**
* Abstract base class implementing the common {@link CacheManager}
* methods. Useful for 'static' environments where the backing caches do
* not change.
* Abstract base class implementing the common {@link CacheManager} methods.
* Useful for 'static' environments where the backing caches do not change.
*
* @author Costin Leau
* @author Juergen Hoeller
@@ -39,9 +38,9 @@ import org.springframework.util.Assert;
*/
public abstract class AbstractCacheManager implements CacheManager, InitializingBean {
private final ConcurrentMap<String, Cache> cacheMap = new ConcurrentHashMap<String, Cache>();
private final ConcurrentMap<String, Cache> cacheMap = new ConcurrentHashMap<String, Cache>(16);
private Set<String> cacheNames = new LinkedHashSet<String>();
private Set<String> cacheNames = new LinkedHashSet<String>(16);
public void afterPropertiesSet() {

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2011 the original author or authors.
* Copyright 2002-2012 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -39,8 +39,36 @@ import org.springframework.cache.CacheManager;
*/
public class NoOpCacheManager implements CacheManager {
private final ConcurrentMap<String, Cache> caches = new ConcurrentHashMap<String, Cache>();
private Set<String> names = new LinkedHashSet<String>();
private final ConcurrentMap<String, Cache> caches = new ConcurrentHashMap<String, Cache>(16);
private final Set<String> cacheNames = new LinkedHashSet<String>(16);
/**
* This implementation always returns a {@link Cache} implementation that will not store items.
* Additionally, the request cache will be remembered by the manager for consistency.
*/
public Cache getCache(String name) {
Cache cache = this.caches.get(name);
if (cache == null) {
this.caches.putIfAbsent(name, new NoOpCache(name));
synchronized (this.cacheNames) {
this.cacheNames.add(name);
}
}
return this.caches.get(name);
}
/**
* This implementation returns the name of the caches previously requested.
*/
public Collection<String> getCacheNames() {
synchronized (this.cacheNames) {
return Collections.unmodifiableSet(this.cacheNames);
}
}
private static class NoOpCache implements Cache {
@@ -61,7 +89,7 @@ public class NoOpCacheManager implements CacheManager {
}
public String getName() {
return name;
return this.name;
}
public Object getNativeCache() {
@@ -72,30 +100,4 @@ public class NoOpCacheManager implements CacheManager {
}
}
/**
* {@inheritDoc}
*
* This implementation always returns a {@link Cache} implementation that will not
* store items. Additionally, the request cache will be remembered by the manager for consistency.
*/
public Cache getCache(String name) {
Cache cache = caches.get(name);
if (cache == null) {
caches.putIfAbsent(name, new NoOpCache(name));
synchronized (names) {
names.add(name);
}
}
return caches.get(name);
}
/**
* {@inheritDoc}
*
* This implementation returns the name of the caches previously requested.
*/
public Collection<String> getCacheNames() {
return Collections.unmodifiableSet(names);
}
}

View File

@@ -178,7 +178,7 @@ public class CommonAnnotationBeanPostProcessor extends InitDestroyAnnotationBean
private transient BeanFactory beanFactory;
private transient final Map<Class<?>, InjectionMetadata> injectionMetadataCache =
new ConcurrentHashMap<Class<?>, InjectionMetadata>();
new ConcurrentHashMap<Class<?>, InjectionMetadata>(64);
/**
@@ -513,10 +513,6 @@ public class CommonAnnotationBeanPostProcessor extends InitDestroyAnnotationBean
protected boolean shareable = true;
private volatile boolean cached = false;
private volatile Object cachedFieldValue;
public ResourceElement(Member member, PropertyDescriptor pd) {
super(member, pd);
}

View File

@@ -53,7 +53,7 @@ public abstract class AbstractApplicationEventMulticaster implements Application
private final ListenerRetriever defaultRetriever = new ListenerRetriever(false);
private final Map<ListenerCacheKey, ListenerRetriever> retrieverCache =
new ConcurrentHashMap<ListenerCacheKey, ListenerRetriever>();
new ConcurrentHashMap<ListenerCacheKey, ListenerRetriever>(64);
private BeanFactory beanFactory;

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2002-2010 the original author or authors.
* Copyright 2002-2012 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -60,10 +60,10 @@ public class StandardBeanExpressionResolver implements BeanExpressionResolver {
private ExpressionParser expressionParser = new SpelExpressionParser();
private final Map<String, Expression> expressionCache = new ConcurrentHashMap<String, Expression>();
private final Map<String, Expression> expressionCache = new ConcurrentHashMap<String, Expression>(256);
private final Map<BeanExpressionContext, StandardEvaluationContext> evaluationCache =
new ConcurrentHashMap<BeanExpressionContext, StandardEvaluationContext>();
new ConcurrentHashMap<BeanExpressionContext, StandardEvaluationContext>(8);
private final ParserContext beanExpressionParserContext = new ParserContext() {
public boolean isTemplate() {

View File

@@ -1387,7 +1387,7 @@ public abstract class AbstractApplicationContext extends DefaultResourceLoader
*/
private class ApplicationListenerDetector implements MergedBeanDefinitionPostProcessor {
private final Map<String, Boolean> singletonNames = new ConcurrentHashMap<String, Boolean>();
private final Map<String, Boolean> singletonNames = new ConcurrentHashMap<String, Boolean>(64);
public void postProcessMergedBeanDefinition(RootBeanDefinition beanDefinition, Class<?> beanType, String beanName) {
if (beanDefinition.isSingleton()) {

View File

@@ -53,10 +53,10 @@ public class FormattingConversionService extends GenericConversionService
private StringValueResolver embeddedValueResolver;
private final Map<AnnotationConverterKey, GenericConverter> cachedPrinters =
new ConcurrentHashMap<AnnotationConverterKey, GenericConverter>();
new ConcurrentHashMap<AnnotationConverterKey, GenericConverter>(64);
private final Map<AnnotationConverterKey, GenericConverter> cachedParsers =
new ConcurrentHashMap<AnnotationConverterKey, GenericConverter>();
new ConcurrentHashMap<AnnotationConverterKey, GenericConverter>(64);
public void setEmbeddedValueResolver(StringValueResolver resolver) {
@@ -214,11 +214,14 @@ public class FormattingConversionService extends GenericConversionService
return sourceType.hasAnnotation(annotationType);
}
@SuppressWarnings("unchecked")
public Object convert(Object source, TypeDescriptor sourceType, TypeDescriptor targetType) {
AnnotationConverterKey converterKey = new AnnotationConverterKey(sourceType.getAnnotation(annotationType), sourceType.getObjectType());
AnnotationConverterKey converterKey =
new AnnotationConverterKey(sourceType.getAnnotation(annotationType), sourceType.getObjectType());
GenericConverter converter = cachedPrinters.get(converterKey);
if (converter == null) {
Printer<?> printer = annotationFormatterFactory.getPrinter(converterKey.getAnnotation(), converterKey.getFieldType());
Printer<?> printer = annotationFormatterFactory.getPrinter(
converterKey.getAnnotation(), converterKey.getFieldType());
converter = new PrinterConverter(fieldType, printer, FormattingConversionService.this);
cachedPrinters.put(converterKey, converter);
}
@@ -226,7 +229,8 @@ public class FormattingConversionService extends GenericConversionService
}
public String toString() {
return "@" + annotationType.getName() + " " + fieldType.getName() + " -> " + String.class.getName() + ": " + annotationFormatterFactory;
return "@" + annotationType.getName() + " " + fieldType.getName() + " -> " +
String.class.getName() + ": " + annotationFormatterFactory;
}
}
@@ -254,11 +258,14 @@ public class FormattingConversionService extends GenericConversionService
return targetType.hasAnnotation(annotationType);
}
@SuppressWarnings("unchecked")
public Object convert(Object source, TypeDescriptor sourceType, TypeDescriptor targetType) {
AnnotationConverterKey converterKey = new AnnotationConverterKey(targetType.getAnnotation(annotationType), targetType.getObjectType());
AnnotationConverterKey converterKey =
new AnnotationConverterKey(targetType.getAnnotation(annotationType), targetType.getObjectType());
GenericConverter converter = cachedParsers.get(converterKey);
if (converter == null) {
Parser<?> parser = annotationFormatterFactory.getParser(converterKey.getAnnotation(), converterKey.getFieldType());
Parser<?> parser = annotationFormatterFactory.getParser(
converterKey.getAnnotation(), converterKey.getFieldType());
converter = new ParserConverter(fieldType, parser, FormattingConversionService.this);
cachedParsers.put(converterKey, converter);
}
@@ -266,7 +273,8 @@ public class FormattingConversionService extends GenericConversionService
}
public String toString() {
return String.class.getName() + " -> @" + annotationType.getName() + " " + fieldType.getName() + ": " + annotationFormatterFactory;
return String.class.getName() + " -> @" + annotationType.getName() + " " +
fieldType.getName() + ": " + annotationFormatterFactory;
}
}