修复ConcurrentHashMap.computeIfAbsent缺陷导致的问题

This commit is contained in:
Looly 2022-09-15 01:35:34 +08:00
parent 3fd1ebe0f5
commit 920fe44e50
5 changed files with 15 additions and 17 deletions

View File

@ -18,6 +18,7 @@
* 【db 】 修复Hive2驱动无法识别问题issue#2606@Github * 【db 】 修复Hive2驱动无法识别问题issue#2606@Github
* 【core 】 修复computeIfAbsent问题issue#I5PTN3@Gitee * 【core 】 修复computeIfAbsent问题issue#I5PTN3@Gitee
* 【extra 】 修复Ftp中路径问题issue#I5R2DE@Gitee * 【extra 】 修复Ftp中路径问题issue#I5R2DE@Gitee
* 【core 】 修复ConcurrentHashMap.computeIfAbsent缺陷导致的问题
------------------------------------------------------------------------------------------------------------- -------------------------------------------------------------------------------------------------------------

View File

@ -1,6 +1,7 @@
package cn.hutool.core.bean; package cn.hutool.core.bean;
import cn.hutool.core.lang.func.Func0; import cn.hutool.core.lang.func.Func0;
import cn.hutool.core.map.MapUtil;
import cn.hutool.core.map.WeakConcurrentMap; import cn.hutool.core.map.WeakConcurrentMap;
/** /**
@ -23,7 +24,7 @@ public enum BeanDescCache {
* @since 5.4.2 * @since 5.4.2
*/ */
public BeanDesc getBeanDesc(Class<?> beanClass, Func0<BeanDesc> supplier) { public BeanDesc getBeanDesc(Class<?> beanClass, Func0<BeanDesc> supplier) {
return bdCache.computeIfAbsent(beanClass, (key)->supplier.callWithRuntimeException()); return MapUtil.computeIfAbsent(bdCache, beanClass, (key)->supplier.callWithRuntimeException());
} }
/** /**

View File

@ -1,6 +1,7 @@
package cn.hutool.core.lang; package cn.hutool.core.lang;
import cn.hutool.core.lang.func.Func0; import cn.hutool.core.lang.func.Func0;
import cn.hutool.core.map.MapUtil;
import cn.hutool.core.util.ArrayUtil; import cn.hutool.core.util.ArrayUtil;
import cn.hutool.core.util.ClassUtil; import cn.hutool.core.util.ClassUtil;
import cn.hutool.core.util.ReflectUtil; import cn.hutool.core.util.ReflectUtil;
@ -52,15 +53,7 @@ public final class Singleton {
*/ */
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
public static <T> T get(String key, Func0<T> supplier) { public static <T> T get(String key, Func0<T> supplier) {
//return (T) POOL.computeIfAbsent(key, (k)-> supplier.callWithRuntimeException()); return (T) MapUtil.computeIfAbsent(POOL, 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;
} }
/** /**

View File

@ -1464,17 +1464,19 @@ public class MapUtil {
} }
/** /**
* 方法来自MyBatis解决使用ConcurrentHashMap.computeIfAbsent导致的死循环问题<br> * 方法来自Dubbo解决使用ConcurrentHashMap.computeIfAbsent导致的死循环问题<br>
* issues#2349<br>
* A temporary workaround for Java 8 specific performance issue JDK-8161372 .<br> * A temporary workaround for Java 8 specific performance issue JDK-8161372 .<br>
* This class should be removed once we drop Java 8 support. * 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> * @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) { public static <K, V> V computeIfAbsent(Map<K, V> map, K key, Function<K, V> mappingFunction) {
final V value = map.get(key); V value = map.get(key);
if (value != null) { if(null == value){
map.putIfAbsent(key, mappingFunction.apply(key));
value = map.get(key);
}
return value; return value;
} }
return map.computeIfAbsent(key, mappingFunction);
}
} }

View File

@ -5,6 +5,7 @@ import cn.hutool.core.exceptions.UtilException;
import cn.hutool.core.lang.Assert; import cn.hutool.core.lang.Assert;
import cn.hutool.core.lang.JarClassLoader; import cn.hutool.core.lang.JarClassLoader;
import cn.hutool.core.lang.Pair; import cn.hutool.core.lang.Pair;
import cn.hutool.core.map.MapUtil;
import cn.hutool.core.map.WeakConcurrentMap; import cn.hutool.core.map.WeakConcurrentMap;
import cn.hutool.core.text.CharPool; import cn.hutool.core.text.CharPool;
@ -50,7 +51,7 @@ public class ClassLoaderUtil {
* 原始类型名和其class对应表例如int = int.class * 原始类型名和其class对应表例如int = int.class
*/ */
private static final Map<String, Class<?>> PRIMITIVE_TYPE_NAME_MAP = new ConcurrentHashMap<>(32); 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 { static {
List<Class<?>> primitiveTypes = new ArrayList<>(32); List<Class<?>> primitiveTypes = new ArrayList<>(32);
@ -199,7 +200,7 @@ public class ClassLoaderUtil {
if (clazz == null) { if (clazz == null) {
final String finalName = name; final String finalName = name;
final ClassLoader finalClassLoader = classLoader; 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; return clazz;
} }