Skip to content

Commit b9df7d6

Browse files
committed
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).
1 parent a2f8902 commit b9df7d6

File tree

58 files changed

+380
-387
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

58 files changed

+380
-387
lines changed

spring-aop/src/main/java/org/springframework/aop/framework/AbstractAdvisingBeanPostProcessor.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,7 @@ public abstract class AbstractAdvisingBeanPostProcessor extends ProxyConfig
4646
*/
4747
private int order = Ordered.LOWEST_PRECEDENCE;
4848

49-
private final Map<String, Boolean> eligibleBeans = new ConcurrentHashMap<String, Boolean>();
49+
private final Map<String, Boolean> eligibleBeans = new ConcurrentHashMap<String, Boolean>(64);
5050

5151

5252
public void setBeanClassLoader(ClassLoader beanClassLoader) {

spring-aop/src/main/java/org/springframework/aop/framework/autoproxy/AbstractAutoProxyCreator.java

Lines changed: 18 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2009 the original author or authors.
2+
* Copyright 2002-2012 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -20,11 +20,8 @@
2020
import java.lang.reflect.Constructor;
2121
import java.util.ArrayList;
2222
import java.util.Arrays;
23-
import java.util.Collections;
24-
import java.util.HashSet;
2523
import java.util.List;
2624
import java.util.Map;
27-
import java.util.Set;
2825
import java.util.concurrent.ConcurrentHashMap;
2926

3027
import org.aopalliance.aop.Advice;
@@ -136,15 +133,15 @@ public abstract class AbstractAutoProxyCreator extends ProxyConfig
136133

137134
private BeanFactory beanFactory;
138135

139-
private final Set<Object> targetSourcedBeans = Collections.synchronizedSet(new HashSet<Object>());
136+
private final Map<Object, Boolean> advisedBeans = new ConcurrentHashMap<Object, Boolean>(64);
140137

141-
private final Set<Object> earlyProxyReferences = Collections.synchronizedSet(new HashSet<Object>());
138+
// using a ConcurrentHashMap as a Set
139+
private final Map<String, Boolean> targetSourcedBeans = new ConcurrentHashMap<String, Boolean>(16);
142140

143-
private final Set<Object> advisedBeans = Collections.synchronizedSet(new HashSet<Object>());
141+
// using a ConcurrentHashMap as a Set
142+
private final Map<Object, Boolean> earlyProxyReferences = new ConcurrentHashMap<Object, Boolean>(16);
144143

145-
private final Set<Object> nonAdvisedBeans = Collections.synchronizedSet(new HashSet<Object>());
146-
147-
private final Map<Object, Class<?>> proxyTypes = new ConcurrentHashMap<Object, Class<?>>();
144+
private final Map<Object, Class<?>> proxyTypes = new ConcurrentHashMap<Object, Class<?>>(16);
148145

149146

150147
/**
@@ -264,19 +261,19 @@ public Constructor<?>[] determineCandidateConstructors(Class<?> beanClass, Strin
264261

265262
public Object getEarlyBeanReference(Object bean, String beanName) throws BeansException {
266263
Object cacheKey = getCacheKey(bean.getClass(), beanName);
267-
this.earlyProxyReferences.add(cacheKey);
264+
this.earlyProxyReferences.put(cacheKey, Boolean.TRUE);
268265
return wrapIfNecessary(bean, beanName, cacheKey);
269266
}
270267

271268
public Object postProcessBeforeInstantiation(Class<?> beanClass, String beanName) throws BeansException {
272269
Object cacheKey = getCacheKey(beanClass, beanName);
273270

274-
if (!this.targetSourcedBeans.contains(cacheKey)) {
275-
if (this.advisedBeans.contains(cacheKey) || this.nonAdvisedBeans.contains(cacheKey)) {
271+
if (!this.targetSourcedBeans.containsKey(beanName)) {
272+
if (this.advisedBeans.containsKey(cacheKey)) {
276273
return null;
277274
}
278275
if (isInfrastructureClass(beanClass) || shouldSkip(beanClass, beanName)) {
279-
this.nonAdvisedBeans.add(cacheKey);
276+
this.advisedBeans.put(cacheKey, Boolean.FALSE);
280277
return null;
281278
}
282279
}
@@ -286,7 +283,7 @@ public Object postProcessBeforeInstantiation(Class<?> beanClass, String beanName
286283
// The TargetSource will handle target instances in a custom fashion.
287284
TargetSource targetSource = getCustomTargetSource(beanClass, beanName);
288285
if (targetSource != null) {
289-
this.targetSourcedBeans.add(beanName);
286+
this.targetSourcedBeans.put(beanName, Boolean.TRUE);
290287
Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(beanClass, beanName, targetSource);
291288
Object proxy = createProxy(beanClass, beanName, specificInterceptors, targetSource);
292289
this.proxyTypes.put(cacheKey, proxy.getClass());
@@ -318,7 +315,7 @@ public Object postProcessBeforeInitialization(Object bean, String beanName) {
318315
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
319316
if (bean != null) {
320317
Object cacheKey = getCacheKey(bean.getClass(), beanName);
321-
if (!this.earlyProxyReferences.contains(cacheKey)) {
318+
if (!this.earlyProxyReferences.containsKey(cacheKey)) {
322319
return wrapIfNecessary(bean, beanName, cacheKey);
323320
}
324321
}
@@ -344,27 +341,27 @@ protected Object getCacheKey(Class<?> beanClass, String beanName) {
344341
* @return a proxy wrapping the bean, or the raw bean instance as-is
345342
*/
346343
protected Object wrapIfNecessary(Object bean, String beanName, Object cacheKey) {
347-
if (this.targetSourcedBeans.contains(beanName)) {
344+
if (this.targetSourcedBeans.containsKey(beanName)) {
348345
return bean;
349346
}
350-
if (this.nonAdvisedBeans.contains(cacheKey)) {
347+
if (Boolean.FALSE.equals(this.advisedBeans.get(cacheKey))) {
351348
return bean;
352349
}
353350
if (isInfrastructureClass(bean.getClass()) || shouldSkip(bean.getClass(), beanName)) {
354-
this.nonAdvisedBeans.add(cacheKey);
351+
this.advisedBeans.put(cacheKey, Boolean.FALSE);
355352
return bean;
356353
}
357354

358355
// Create proxy if we have advice.
359356
Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(bean.getClass(), beanName, null);
360357
if (specificInterceptors != DO_NOT_PROXY) {
361-
this.advisedBeans.add(cacheKey);
358+
this.advisedBeans.put(cacheKey, Boolean.TRUE);
362359
Object proxy = createProxy(bean.getClass(), beanName, specificInterceptors, new SingletonTargetSource(bean));
363360
this.proxyTypes.put(cacheKey, proxy.getClass());
364361
return proxy;
365362
}
366363

367-
this.nonAdvisedBeans.add(cacheKey);
364+
this.advisedBeans.put(cacheKey, Boolean.FALSE);
368365
return bean;
369366
}
370367

spring-aop/src/main/java/org/springframework/aop/target/ThreadLocalTargetSource.java

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2010 the original author or authors.
2+
* Copyright 2002-2012 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -16,7 +16,6 @@
1616

1717
package org.springframework.aop.target;
1818

19-
import java.util.Collections;
2019
import java.util.HashSet;
2120
import java.util.Set;
2221

@@ -62,7 +61,7 @@ public class ThreadLocalTargetSource extends AbstractPrototypeBasedTargetSource
6261
/**
6362
* Set of managed targets, enabling us to keep track of the targets we've created.
6463
*/
65-
private final Set<Object> targetSet = Collections.synchronizedSet(new HashSet<Object>());
64+
private final Set<Object> targetSet = new HashSet<Object>();
6665

6766
private int invocationCount;
6867

@@ -85,7 +84,9 @@ public Object getTarget() throws BeansException {
8584
// Associate target with ThreadLocal.
8685
target = newPrototypeInstance();
8786
this.targetInThread.set(target);
88-
this.targetSet.add(target);
87+
synchronized (this.targetSet) {
88+
this.targetSet.add(target);
89+
}
8990
}
9091
else {
9192
++this.hitCount;
@@ -119,7 +120,9 @@ public int getHitCount() {
119120
}
120121

121122
public int getObjectCount() {
122-
return this.targetSet.size();
123+
synchronized (this.targetSet) {
124+
return this.targetSet.size();
125+
}
123126
}
124127

125128

spring-beans/src/main/java/org/springframework/beans/BeanUtils.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2010 the original author or authors.
2+
* Copyright 2002-2012 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -57,6 +57,7 @@ public abstract class BeanUtils {
5757

5858
private static final Log logger = LogFactory.getLog(BeanUtils.class);
5959

60+
// using WeakHashMap as a Set
6061
private static final Map<Class<?>, Boolean> unknownEditorTypes =
6162
Collections.synchronizedMap(new WeakHashMap<Class<?>, Boolean>());
6263

spring-beans/src/main/java/org/springframework/beans/CachedIntrospectionResults.java

Lines changed: 19 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,6 @@
2222
import java.beans.PropertyDescriptor;
2323
import java.lang.ref.Reference;
2424
import java.lang.ref.WeakReference;
25-
import java.util.Collections;
2625
import java.util.HashSet;
2726
import java.util.Iterator;
2827
import java.util.LinkedHashMap;
@@ -70,14 +69,14 @@ public class CachedIntrospectionResults {
7069
* Set of ClassLoaders that this CachedIntrospectionResults class will always
7170
* accept classes from, even if the classes do not qualify as cache-safe.
7271
*/
73-
static final Set<ClassLoader> acceptedClassLoaders = Collections.synchronizedSet(new HashSet<ClassLoader>());
72+
static final Set<ClassLoader> acceptedClassLoaders = new HashSet<ClassLoader>();
7473

7574
/**
7675
* Map keyed by class containing CachedIntrospectionResults.
7776
* Needs to be a WeakHashMap with WeakReferences as values to allow
7877
* for proper garbage collection in case of multiple class loaders.
7978
*/
80-
static final Map<Class, Object> classCache = Collections.synchronizedMap(new WeakHashMap<Class, Object>());
79+
static final Map<Class, Object> classCache = new WeakHashMap<Class, Object>();
8180

8281

8382
/**
@@ -94,7 +93,9 @@ public class CachedIntrospectionResults {
9493
*/
9594
public static void acceptClassLoader(ClassLoader classLoader) {
9695
if (classLoader != null) {
97-
acceptedClassLoaders.add(classLoader);
96+
synchronized (acceptedClassLoaders) {
97+
acceptedClassLoaders.add(classLoader);
98+
}
9899
}
99100
}
100101

@@ -137,7 +138,10 @@ public static void clearClassLoader(ClassLoader classLoader) {
137138
*/
138139
static CachedIntrospectionResults forClass(Class beanClass) throws BeansException {
139140
CachedIntrospectionResults results;
140-
Object value = classCache.get(beanClass);
141+
Object value;
142+
synchronized (classCache) {
143+
value = classCache.get(beanClass);
144+
}
141145
if (value instanceof Reference) {
142146
Reference ref = (Reference) value;
143147
results = (CachedIntrospectionResults) ref.get();
@@ -149,14 +153,18 @@ static CachedIntrospectionResults forClass(Class beanClass) throws BeansExceptio
149153
if (ClassUtils.isCacheSafe(beanClass, CachedIntrospectionResults.class.getClassLoader()) ||
150154
isClassLoaderAccepted(beanClass.getClassLoader())) {
151155
results = new CachedIntrospectionResults(beanClass);
152-
classCache.put(beanClass, results);
156+
synchronized (classCache) {
157+
classCache.put(beanClass, results);
158+
}
153159
}
154160
else {
155161
if (logger.isDebugEnabled()) {
156162
logger.debug("Not strongly caching class [" + beanClass.getName() + "] because it is not cache-safe");
157163
}
158164
results = new CachedIntrospectionResults(beanClass);
159-
classCache.put(beanClass, new WeakReference<CachedIntrospectionResults>(results));
165+
synchronized (classCache) {
166+
classCache.put(beanClass, new WeakReference<CachedIntrospectionResults>(results));
167+
}
160168
}
161169
}
162170
return results;
@@ -172,8 +180,10 @@ static CachedIntrospectionResults forClass(Class beanClass) throws BeansExceptio
172180
private static boolean isClassLoaderAccepted(ClassLoader classLoader) {
173181
// Iterate over array copy in order to avoid synchronization for the entire
174182
// ClassLoader check (avoiding a synchronized acceptedClassLoaders Iterator).
175-
ClassLoader[] acceptedLoaderArray =
176-
acceptedClassLoaders.toArray(new ClassLoader[acceptedClassLoaders.size()]);
183+
ClassLoader[] acceptedLoaderArray;
184+
synchronized (acceptedClassLoaders) {
185+
acceptedLoaderArray = acceptedClassLoaders.toArray(new ClassLoader[acceptedClassLoaders.size()]);
186+
}
177187
for (ClassLoader registeredLoader : acceptedLoaderArray) {
178188
if (isUnderneathClassLoader(classLoader, registeredLoader)) {
179189
return true;

spring-beans/src/main/java/org/springframework/beans/factory/annotation/AutowiredAnnotationBeanPostProcessor.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -119,10 +119,10 @@ public class AutowiredAnnotationBeanPostProcessor extends InstantiationAwareBean
119119
private ConfigurableListableBeanFactory beanFactory;
120120

121121
private final Map<Class<?>, Constructor<?>[]> candidateConstructorsCache =
122-
new ConcurrentHashMap<Class<?>, Constructor<?>[]>();
122+
new ConcurrentHashMap<Class<?>, Constructor<?>[]>(64);
123123

124124
private final Map<Class<?>, InjectionMetadata> injectionMetadataCache =
125-
new ConcurrentHashMap<Class<?>, InjectionMetadata>();
125+
new ConcurrentHashMap<Class<?>, InjectionMetadata>(64);
126126

127127

128128
/**

0 commit comments

Comments
 (0)