Skip to content

Commit 0262a99

Browse files
authored
Merge pull request #2223 from harawata/workaround-jdk-8161372
Prevent thread from being blocked by JDK-8 ConcurrentHashMap#computeIfAbsent()
2 parents f6caf12 + 2fc8ec0 commit 0262a99

File tree

9 files changed

+66
-24
lines changed

9 files changed

+66
-24
lines changed

src/main/java/org/apache/ibatis/binding/MapperProxy.java

Lines changed: 3 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/**
2-
* Copyright 2009-2020 the original author or authors.
2+
* Copyright 2009-2021 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.
@@ -28,6 +28,7 @@
2828

2929
import org.apache.ibatis.reflection.ExceptionUtil;
3030
import org.apache.ibatis.session.SqlSession;
31+
import org.apache.ibatis.util.MapUtil;
3132

3233
/**
3334
* @author Clinton Begin
@@ -91,15 +92,7 @@ public Object invoke(Object proxy, Method method, Object[] args) throws Throwabl
9192

9293
private MapperMethodInvoker cachedInvoker(Method method) throws Throwable {
9394
try {
94-
// A workaround for https://bugs.openjdk.java.net/browse/JDK-8161372
95-
// It should be removed once the fix is backported to Java 8 or
96-
// MyBatis drops Java 8 support. See gh-1929
97-
MapperMethodInvoker invoker = methodCache.get(method);
98-
if (invoker != null) {
99-
return invoker;
100-
}
101-
102-
return methodCache.computeIfAbsent(method, m -> {
95+
return MapUtil.computeIfAbsent(methodCache, method, m -> {
10396
if (m.isDefault()) {
10497
try {
10598
if (privateLookupInMethod == null) {

src/main/java/org/apache/ibatis/cache/TransactionalCacheManager.java

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/**
2-
* Copyright 2009-2019 the original author or authors.
2+
* Copyright 2009-2021 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.
@@ -19,6 +19,7 @@
1919
import java.util.Map;
2020

2121
import org.apache.ibatis.cache.decorators.TransactionalCache;
22+
import org.apache.ibatis.util.MapUtil;
2223

2324
/**
2425
* @author Clinton Begin
@@ -52,7 +53,7 @@ public void rollback() {
5253
}
5354

5455
private TransactionalCache getTransactionalCache(Cache cache) {
55-
return transactionalCaches.computeIfAbsent(cache, TransactionalCache::new);
56+
return MapUtil.computeIfAbsent(transactionalCaches, cache, TransactionalCache::new);
5657
}
5758

5859
}

src/main/java/org/apache/ibatis/executor/keygen/Jdbc3KeyGenerator.java

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/**
2-
* Copyright 2009-2020 the original author or authors.
2+
* Copyright 2009-2021 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.
@@ -42,6 +42,7 @@
4242
import org.apache.ibatis.type.JdbcType;
4343
import org.apache.ibatis.type.TypeHandler;
4444
import org.apache.ibatis.type.TypeHandlerRegistry;
45+
import org.apache.ibatis.util.MapUtil;
4546

4647
/**
4748
* @author Clinton Begin
@@ -156,7 +157,7 @@ private void assignKeysToParamMap(Configuration configuration, ResultSet rs, Res
156157
for (int i = 0; i < keyProperties.length; i++) {
157158
Entry<String, KeyAssigner> entry = getAssignerForParamMap(configuration, rsmd, i + 1, paramMap, keyProperties[i],
158159
keyProperties, true);
159-
Entry<Iterator<?>, List<KeyAssigner>> iteratorPair = assignerMap.computeIfAbsent(entry.getKey(),
160+
Entry<Iterator<?>, List<KeyAssigner>> iteratorPair = MapUtil.computeIfAbsent(assignerMap, entry.getKey(),
160161
k -> entry(collectionize(paramMap.get(k)).iterator(), new ArrayList<>()));
161162
iteratorPair.getValue().add(entry.getValue());
162163
}

src/main/java/org/apache/ibatis/executor/resultset/DefaultResultSetHandler.java

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/**
2-
* Copyright 2009-2020 the original author or authors.
2+
* Copyright 2009-2021 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.
@@ -61,6 +61,7 @@
6161
import org.apache.ibatis.type.JdbcType;
6262
import org.apache.ibatis.type.TypeHandler;
6363
import org.apache.ibatis.type.TypeHandlerRegistry;
64+
import org.apache.ibatis.util.MapUtil;
6465

6566
/**
6667
* @author Clinton Begin
@@ -589,7 +590,7 @@ private void addPendingChildRelation(ResultSet rs, MetaObject metaResultObject,
589590
PendingRelation deferLoad = new PendingRelation();
590591
deferLoad.metaObject = metaResultObject;
591592
deferLoad.propertyMapping = parentMapping;
592-
List<PendingRelation> relations = pendingRelations.computeIfAbsent(cacheKey, k -> new ArrayList<>());
593+
List<PendingRelation> relations = MapUtil.computeIfAbsent(pendingRelations, cacheKey, k -> new ArrayList<>());
593594
// issue #255
594595
relations.add(deferLoad);
595596
ResultMapping previous = nextResultMaps.get(parentMapping.getResultSet());

src/main/java/org/apache/ibatis/plugin/Plugin.java

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/**
2-
* Copyright 2009-2020 the original author or authors.
2+
* Copyright 2009-2021 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.
@@ -24,6 +24,7 @@
2424
import java.util.Set;
2525

2626
import org.apache.ibatis.reflection.ExceptionUtil;
27+
import org.apache.ibatis.util.MapUtil;
2728

2829
/**
2930
* @author Clinton Begin
@@ -75,7 +76,7 @@ private static Map<Class<?>, Set<Method>> getSignatureMap(Interceptor intercepto
7576
Signature[] sigs = interceptsAnnotation.value();
7677
Map<Class<?>, Set<Method>> signatureMap = new HashMap<>();
7778
for (Signature sig : sigs) {
78-
Set<Method> methods = signatureMap.computeIfAbsent(sig.type(), k -> new HashSet<>());
79+
Set<Method> methods = MapUtil.computeIfAbsent(signatureMap, sig.type(), k -> new HashSet<>());
7980
try {
8081
Method method = sig.type().getMethod(sig.method(), sig.args());
8182
methods.add(method);

src/main/java/org/apache/ibatis/reflection/DefaultReflectorFactory.java

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/**
2-
* Copyright 2009-2019 the original author or authors.
2+
* Copyright 2009-2021 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.
@@ -18,6 +18,8 @@
1818
import java.util.concurrent.ConcurrentHashMap;
1919
import java.util.concurrent.ConcurrentMap;
2020

21+
import org.apache.ibatis.util.MapUtil;
22+
2123
public class DefaultReflectorFactory implements ReflectorFactory {
2224
private boolean classCacheEnabled = true;
2325
private final ConcurrentMap<Class<?>, Reflector> reflectorMap = new ConcurrentHashMap<>();
@@ -39,7 +41,7 @@ public void setClassCacheEnabled(boolean classCacheEnabled) {
3941
public Reflector findForClass(Class<?> type) {
4042
if (classCacheEnabled) {
4143
// synchronized (type) removed see issue #461
42-
return reflectorMap.computeIfAbsent(type, Reflector::new);
44+
return MapUtil.computeIfAbsent(reflectorMap, type, Reflector::new);
4345
} else {
4446
return new Reflector(type);
4547
}

src/main/java/org/apache/ibatis/reflection/Reflector.java

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/**
2-
* Copyright 2009-2020 the original author or authors.
2+
* Copyright 2009-2021 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.
@@ -40,6 +40,7 @@
4040
import org.apache.ibatis.reflection.invoker.MethodInvoker;
4141
import org.apache.ibatis.reflection.invoker.SetFieldInvoker;
4242
import org.apache.ibatis.reflection.property.PropertyNamer;
43+
import org.apache.ibatis.util.MapUtil;
4344

4445
/**
4546
* This class represents a cached set of class definition information that
@@ -143,7 +144,7 @@ private void addSetMethods(Class<?> clazz) {
143144

144145
private void addMethodConflict(Map<String, List<Method>> conflictingMethods, String name, Method method) {
145146
if (isValidPropertyName(name)) {
146-
List<Method> list = conflictingMethods.computeIfAbsent(name, k -> new ArrayList<>());
147+
List<Method> list = MapUtil.computeIfAbsent(conflictingMethods, name, k -> new ArrayList<>());
147148
list.add(method);
148149
}
149150
}

src/main/java/org/apache/ibatis/scripting/LanguageDriverRegistry.java

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/**
2-
* Copyright 2009-2019 the original author or authors.
2+
* Copyright 2009-2021 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.
@@ -18,6 +18,8 @@
1818
import java.util.HashMap;
1919
import java.util.Map;
2020

21+
import org.apache.ibatis.util.MapUtil;
22+
2123
/**
2224
* @author Frank D. Martinez [mnesarco]
2325
*/
@@ -31,7 +33,7 @@ public void register(Class<? extends LanguageDriver> cls) {
3133
if (cls == null) {
3234
throw new IllegalArgumentException("null is not a valid Language Driver");
3335
}
34-
LANGUAGE_DRIVER_MAP.computeIfAbsent(cls, k -> {
36+
MapUtil.computeIfAbsent(LANGUAGE_DRIVER_MAP, cls, k -> {
3537
try {
3638
return k.getDeclaredConstructor().newInstance();
3739
} catch (Exception ex) {
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
/**
2+
* Copyright 2009-2021 the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package org.apache.ibatis.util;
18+
19+
import java.util.Map;
20+
import java.util.function.Function;
21+
22+
public class MapUtil {
23+
/**
24+
* A temporary workaround for Java 8 specific performance issue JDK-8161372 .<br>
25+
* This class should be removed once we drop Java 8 support.
26+
*
27+
* @see <a href="https://bugs.openjdk.java.net/browse/JDK-8161372">https://bugs.openjdk.java.net/browse/JDK-8161372</a>
28+
*/
29+
public static <K, V> V computeIfAbsent(Map<K, V> map, K key, Function<K, V> mappingFunction) {
30+
V value = map.get(key);
31+
if (value != null) {
32+
return value;
33+
}
34+
return map.computeIfAbsent(key, mappingFunction::apply);
35+
}
36+
37+
private MapUtil() {
38+
super();
39+
}
40+
}

0 commit comments

Comments
 (0)