Skip to content

Commit

Permalink
修复ConcurrentHashMap.computeIfAbsent缺陷导致的问题
Browse files Browse the repository at this point in the history
  • Loading branch information
looly committed Sep 14, 2022
1 parent 3fd1ebe commit 920fe44
Show file tree
Hide file tree
Showing 5 changed files with 15 additions and 17 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Expand Up @@ -18,6 +18,7 @@
* 【db 】 修复Hive2驱动无法识别问题(issue#2606@Github)
* 【core 】 修复computeIfAbsent问题(issue#I5PTN3@Gitee)
* 【extra 】 修复Ftp中路径问题(issue#I5R2DE@Gitee)
* 【core 】 修复ConcurrentHashMap.computeIfAbsent缺陷导致的问题

-------------------------------------------------------------------------------------------------------------

Expand Down
@@ -1,6 +1,7 @@
package cn.hutool.core.bean;

import cn.hutool.core.lang.func.Func0;
import cn.hutool.core.map.MapUtil;
import cn.hutool.core.map.WeakConcurrentMap;

/**
Expand All @@ -23,7 +24,7 @@ public enum BeanDescCache {
* @since 5.4.2
*/
public BeanDesc getBeanDesc(Class<?> beanClass, Func0<BeanDesc> supplier) {
return bdCache.computeIfAbsent(beanClass, (key)->supplier.callWithRuntimeException());
return MapUtil.computeIfAbsent(bdCache, beanClass, (key)->supplier.callWithRuntimeException());
}

/**
Expand Down
11 changes: 2 additions & 9 deletions hutool-core/src/main/java/cn/hutool/core/lang/Singleton.java
@@ -1,6 +1,7 @@
package cn.hutool.core.lang;

import cn.hutool.core.lang.func.Func0;
import cn.hutool.core.map.MapUtil;
import cn.hutool.core.util.ArrayUtil;
import cn.hutool.core.util.ClassUtil;
import cn.hutool.core.util.ReflectUtil;
Expand Down Expand Up @@ -52,15 +53,7 @@ public static <T> T get(Class<T> clazz, Object... params) {
*/
@SuppressWarnings("unchecked")
public static <T> T get(String key, Func0<T> supplier) {
//return (T) POOL.computeIfAbsent(key, (k)-> supplier.callWithRuntimeException());
// issues#2349
// ConcurrentHashMap.computeIfAbsent在某些情况下会导致死循环问题,此处采用Dubbo的解决方案
Object value = POOL.get(key);
if(null == value){
POOL.putIfAbsent(key, supplier.callWithRuntimeException());
value = POOL.get(key);
}
return (T) value;
return (T) MapUtil.computeIfAbsent(POOL, key, (k)-> supplier.callWithRuntimeException());
}

/**
Expand Down
12 changes: 7 additions & 5 deletions hutool-core/src/main/java/cn/hutool/core/map/MapUtil.java
Expand Up @@ -1464,17 +1464,19 @@ public static <K, V> Map.Entry<K, V> entry(K key, V value, boolean isImmutable)
}

/**
* 方法来自MyBatis,解决使用ConcurrentHashMap.computeIfAbsent导致的死循环问题。<br>
* 方法来自Dubbo,解决使用ConcurrentHashMap.computeIfAbsent导致的死循环问题。<br>
* issues#2349<br>
* A temporary workaround for Java 8 specific performance issue JDK-8161372 .<br>
* This class should be removed once we drop Java 8 support.
*
* @see <a href="https://bugs.openjdk.java.net/browse/JDK-8161372">https://bugs.openjdk.java.net/browse/JDK-8161372</a>
*/
public static <K, V> V computeIfAbsent(Map<K, V> map, K key, Function<K, V> mappingFunction) {
final V value = map.get(key);
if (value != null) {
return value;
V value = map.get(key);
if(null == value){
map.putIfAbsent(key, mappingFunction.apply(key));
value = map.get(key);
}
return map.computeIfAbsent(key, mappingFunction);
return value;
}
}
Expand Up @@ -5,6 +5,7 @@
import cn.hutool.core.lang.Assert;
import cn.hutool.core.lang.JarClassLoader;
import cn.hutool.core.lang.Pair;
import cn.hutool.core.map.MapUtil;
import cn.hutool.core.map.WeakConcurrentMap;
import cn.hutool.core.text.CharPool;

Expand Down Expand Up @@ -50,7 +51,7 @@ public class ClassLoaderUtil {
* 原始类型名和其class对应表,例如:int =》 int.class
*/
private static final Map<String, Class<?>> PRIMITIVE_TYPE_NAME_MAP = new ConcurrentHashMap<>(32);
private static final WeakConcurrentMap<Pair<String, ClassLoader>, Class<?>> CLASS_CACHE = new WeakConcurrentMap<>();
private static final Map<Pair<String, ClassLoader>, Class<?>> CLASS_CACHE = new WeakConcurrentMap<>();

static {
List<Class<?>> primitiveTypes = new ArrayList<>(32);
Expand Down Expand Up @@ -199,7 +200,7 @@ public static Class<?> loadClass(String name, ClassLoader classLoader, boolean i
if (clazz == null) {
final String finalName = name;
final ClassLoader finalClassLoader = classLoader;
clazz = CLASS_CACHE.computeIfAbsent(Pair.of(name, classLoader), (key)-> doLoadClass(finalName, finalClassLoader, isInitialized));
clazz = MapUtil.computeIfAbsent(CLASS_CACHE, Pair.of(name, classLoader), (key)-> doLoadClass(finalName, finalClassLoader, isInitialized));
}
return clazz;
}
Expand Down

0 comments on commit 920fe44

Please sign in to comment.