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

@@ -1,5 +1,5 @@
/*
* Copyright 2002-2009 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.
@@ -27,19 +27,19 @@ import org.springframework.http.converter.HttpMessageConversionException;
import org.springframework.util.Assert;
/**
* Abstract base class for {@link org.springframework.http.converter.HttpMessageConverter HttpMessageConverters} that
* use JAXB2. Creates {@link JAXBContext} object lazily.
* Abstract base class for {@link org.springframework.http.converter.HttpMessageConverter HttpMessageConverters}
* that use JAXB2. Creates {@link JAXBContext} object lazily.
*
* @author Arjen Poutsma
* @since 3.0
*/
public abstract class AbstractJaxb2HttpMessageConverter<T> extends AbstractXmlHttpMessageConverter<T> {
private final ConcurrentMap<Class, JAXBContext> jaxbContexts = new ConcurrentHashMap<Class, JAXBContext>();
private final ConcurrentMap<Class, JAXBContext> jaxbContexts = new ConcurrentHashMap<Class, JAXBContext>(64);
/**
* Creates a new {@link Marshaller} for the given class.
*
* Create a new {@link Marshaller} for the given class.
* @param clazz the class to create the marshaller for
* @return the {@code Marshaller}
* @throws HttpMessageConversionException in case of JAXB errors
@@ -56,8 +56,7 @@ public abstract class AbstractJaxb2HttpMessageConverter<T> extends AbstractXmlHt
}
/**
* Creates a new {@link Unmarshaller} for the given class.
*
* Create a new {@link Unmarshaller} for the given class.
* @param clazz the class to create the unmarshaller for
* @return the {@code Unmarshaller}
* @throws HttpMessageConversionException in case of JAXB errors
@@ -74,19 +73,18 @@ public abstract class AbstractJaxb2HttpMessageConverter<T> extends AbstractXmlHt
}
/**
* Returns a {@link JAXBContext} for the given class.
*
* Return a {@link JAXBContext} for the given class.
* @param clazz the class to return the context for
* @return the {@code JAXBContext}
* @throws HttpMessageConversionException in case of JAXB errors
*/
protected final JAXBContext getJaxbContext(Class clazz) {
Assert.notNull(clazz, "'clazz' must not be null");
JAXBContext jaxbContext = jaxbContexts.get(clazz);
JAXBContext jaxbContext = this.jaxbContexts.get(clazz);
if (jaxbContext == null) {
try {
jaxbContext = JAXBContext.newInstance(clazz);
jaxbContexts.putIfAbsent(clazz, jaxbContext);
this.jaxbContexts.putIfAbsent(clazz, jaxbContext);
}
catch (JAXBException ex) {
throw new HttpMessageConversionException(

View File

@@ -13,10 +13,11 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.web.accept;
import java.util.ArrayList;
import java.util.Collections;
import java.util.LinkedList;
import java.util.List;
import java.util.Locale;
import java.util.Map;
@@ -37,11 +38,12 @@ import org.springframework.util.MultiValueMap;
*/
public class MappingMediaTypeFileExtensionResolver implements MediaTypeFileExtensionResolver {
private final ConcurrentMap<String, MediaType> mediaTypes = new ConcurrentHashMap<String, MediaType>();
private final ConcurrentMap<String, MediaType> mediaTypes = new ConcurrentHashMap<String, MediaType>(64);
private final MultiValueMap<MediaType, String> fileExtensions = new LinkedMultiValueMap<MediaType, String>();
private final List<String> allFileExtensions = new ArrayList<String>();
private final List<String> allFileExtensions = new LinkedList<String>();
/**
* Create an instance with the given mappings between extensions and media types.
@@ -89,4 +91,4 @@ public class MappingMediaTypeFileExtensionResolver implements MediaTypeFileExten
}
}
}
}

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.
@@ -19,10 +19,11 @@ package org.springframework.web.bind.annotation.support;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashSet;
import java.util.LinkedHashSet;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import org.springframework.core.BridgeMethodResolver;
import org.springframework.core.annotation.AnnotationUtils;
@@ -64,7 +65,8 @@ public class HandlerMethodResolver {
private final Set<Class> sessionAttributeTypes = new HashSet<Class>();
private final Set<String> actualSessionAttributeNames = Collections.synchronizedSet(new HashSet<String>(4));
// using a ConcurrentHashMap as a Set
private final Map<String, Boolean> actualSessionAttributeNames = new ConcurrentHashMap<String, Boolean>(4);
/**
@@ -152,7 +154,7 @@ public class HandlerMethodResolver {
public boolean isSessionAttribute(String attrName, Class attrType) {
if (this.sessionAttributeNames.contains(attrName) || this.sessionAttributeTypes.contains(attrType)) {
this.actualSessionAttributeNames.add(attrName);
this.actualSessionAttributeNames.put(attrName, Boolean.TRUE);
return true;
}
else {
@@ -161,7 +163,7 @@ public class HandlerMethodResolver {
}
public Set<String> getActualSessionAttributeNames() {
return this.actualSessionAttributeNames;
return this.actualSessionAttributeNames.keySet();
}
}

View File

@@ -62,7 +62,7 @@ public abstract class AbstractNamedValueMethodArgumentResolver implements Handle
private final BeanExpressionContext expressionContext;
private Map<MethodParameter, NamedValueInfo> namedValueInfoCache =
new ConcurrentHashMap<MethodParameter, NamedValueInfo>();
new ConcurrentHashMap<MethodParameter, NamedValueInfo>(256);
/**
* @param beanFactory a bean factory to use for resolving ${...} placeholder
@@ -80,11 +80,9 @@ public abstract class AbstractNamedValueMethodArgumentResolver implements Handle
throws Exception {
Class<?> paramType = parameter.getParameterType();
NamedValueInfo namedValueInfo = getNamedValueInfo(parameter);
Object arg = resolveName(namedValueInfo.name, parameter, webRequest);
if (arg == null) {
if (namedValueInfo.defaultValue != null) {
arg = resolveDefaultValue(namedValueInfo.defaultValue);
@@ -121,7 +119,6 @@ public abstract class AbstractNamedValueMethodArgumentResolver implements Handle
/**
* Create the {@link NamedValueInfo} object for the given method parameter. Implementations typically
* retrieve the method annotation by means of {@link MethodParameter#getParameterAnnotation(Class)}.
*
* @param parameter the method parameter
* @return the named value information
*/
@@ -146,7 +143,6 @@ public abstract class AbstractNamedValueMethodArgumentResolver implements Handle
* @param name the name of the value being resolved
* @param parameter the method parameter to resolve to an argument value
* @param request the current request
*
* @return the resolved argument. May be {@code null}
* @throws Exception in case of errors
*/
@@ -203,9 +199,9 @@ public abstract class AbstractNamedValueMethodArgumentResolver implements Handle
*/
protected void handleResolvedValue(Object arg, String name, MethodParameter parameter,
ModelAndViewContainer mavContainer, NativeWebRequest webRequest) {
}
/**
* Represents the information about a named value, including name, whether it's required and a default value.
*/
@@ -223,4 +219,5 @@ public abstract class AbstractNamedValueMethodArgumentResolver implements Handle
this.defaultValue = defaultValue;
}
}
}

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.
@@ -46,10 +46,10 @@ public class ExceptionHandlerMethodResolver {
private static final Method NO_METHOD_FOUND = ClassUtils.getMethodIfAvailable(System.class, "currentTimeMillis");
private final Map<Class<? extends Throwable>, Method> mappedMethods =
new ConcurrentHashMap<Class<? extends Throwable>, Method>();
new ConcurrentHashMap<Class<? extends Throwable>, Method>(16);
private final Map<Class<? extends Throwable>, Method> exceptionLookupCache =
new ConcurrentHashMap<Class<? extends Throwable>, Method>();
new ConcurrentHashMap<Class<? extends Throwable>, Method>(16);
/**
* A constructor that finds {@link ExceptionHandler} methods in the given type.

View File

@@ -17,11 +17,11 @@
package org.springframework.web.method.annotation;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import org.springframework.core.annotation.AnnotationUtils;
import org.springframework.util.Assert;
@@ -50,10 +50,12 @@ public class SessionAttributesHandler {
private final Set<Class<?>> attributeTypes = new HashSet<Class<?>>();
private final Set<String> knownAttributeNames = Collections.synchronizedSet(new HashSet<String>(4));
// using a ConcurrentHashMap as a Set
private final Map<String, Boolean> knownAttributeNames = new ConcurrentHashMap<String, Boolean>(4);
private final SessionAttributeStore sessionAttributeStore;
/**
* Create a new instance for a controller type. Session attribute names and
* types are extracted from the {@code @SessionAttributes} annotation, if
@@ -71,7 +73,9 @@ public class SessionAttributesHandler {
this.attributeTypes.addAll(Arrays.<Class<?>>asList(annotation.types()));
}
this.knownAttributeNames.addAll(this.attributeNames);
for (String attributeName : this.attributeNames) {
this.knownAttributeNames.put(attributeName, Boolean.TRUE);
}
}
/**
@@ -96,7 +100,7 @@ public class SessionAttributesHandler {
public boolean isHandlerSessionAttribute(String attributeName, Class<?> attributeType) {
Assert.notNull(attributeName, "Attribute name must not be null");
if (this.attributeNames.contains(attributeName) || this.attributeTypes.contains(attributeType)) {
this.knownAttributeNames.add(attributeName);
this.knownAttributeNames.put(attributeName, Boolean.TRUE);
return true;
}
else {
@@ -130,7 +134,7 @@ public class SessionAttributesHandler {
*/
public Map<String, Object> retrieveAttributes(WebRequest request) {
Map<String, Object> attributes = new HashMap<String, Object>();
for (String name : this.knownAttributeNames) {
for (String name : this.knownAttributeNames.keySet()) {
Object value = this.sessionAttributeStore.retrieveAttribute(request, name);
if (value != null) {
attributes.put(name, value);
@@ -146,7 +150,7 @@ public class SessionAttributesHandler {
* @param request the current request
*/
public void cleanupAttributes(WebRequest request) {
for (String attributeName : this.knownAttributeNames) {
for (String attributeName : this.knownAttributeNames.keySet()) {
this.sessionAttributeStore.cleanupAttribute(request, attributeName);
}
}
@@ -161,4 +165,4 @@ public class SessionAttributesHandler {
return this.sessionAttributeStore.retrieveAttribute(request, attributeName);
}
}
}

View File

@@ -16,14 +16,15 @@
package org.springframework.web.method.support;
import java.util.ArrayList;
import java.util.Collections;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.core.MethodParameter;
import org.springframework.util.Assert;
import org.springframework.web.bind.support.WebDataBinderFactory;
@@ -41,10 +42,11 @@ public class HandlerMethodArgumentResolverComposite implements HandlerMethodArgu
protected final Log logger = LogFactory.getLog(getClass());
private final List<HandlerMethodArgumentResolver> argumentResolvers =
new ArrayList<HandlerMethodArgumentResolver>();
new LinkedList<HandlerMethodArgumentResolver>();
private final Map<MethodParameter, HandlerMethodArgumentResolver> argumentResolverCache =
new ConcurrentHashMap<MethodParameter, HandlerMethodArgumentResolver>();
new ConcurrentHashMap<MethodParameter, HandlerMethodArgumentResolver>(256);
/**
* Return a read-only list with the contained resolvers, or an empty list.
@@ -81,7 +83,7 @@ public class HandlerMethodArgumentResolverComposite implements HandlerMethodArgu
private HandlerMethodArgumentResolver getArgumentResolver(MethodParameter parameter) {
HandlerMethodArgumentResolver result = this.argumentResolverCache.get(parameter);
if (result == null) {
for (HandlerMethodArgumentResolver methodArgumentResolver : argumentResolvers) {
for (HandlerMethodArgumentResolver methodArgumentResolver : this.argumentResolvers) {
if (logger.isTraceEnabled()) {
logger.trace("Testing if argument resolver [" + methodArgumentResolver + "] supports [" +
parameter.getGenericParameterType() + "]");