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:
@@ -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(
|
||||
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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() + "]");
|
||||
|
||||
Reference in New Issue
Block a user