修复MapUtil.computeIfAbsent可能存在的并发问题

This commit is contained in:
Looly 2023-03-31 21:34:05 +08:00
parent 8420a9b0a1
commit 4bc25e92d8
4 changed files with 105 additions and 11 deletions

View File

@ -11,10 +11,12 @@
* 【core 】 NumberUtil增加pr#968@Gitee
* 【core 】 Number128增加hash和equals方法pr#968@Gitee
* 【core 】 NamingCase.toCamelCase新增重载可选是否转换其他字符为小写issue#3031@ithub
* 【core 】 新增JdkUtil
### 🐞Bug修复
* 【core 】 CollUtil.split优化切割列表参数判断避免OOMpr#3026@Github
* 【core 】 修复FileUtil.move传入相同目录或子目录丢失源目录的问题pr#3032@Github
* 【core 】 修复MapUtil.computeIfAbsent可能存在的并发问题issue#I6RVMY@Gitee
-------------------------------------------------------------------------------------------------------------
# 5.8.16 (2023-03-26)

View File

@ -9,6 +9,7 @@ import cn.hutool.core.lang.Pair;
import cn.hutool.core.lang.TypeReference;
import cn.hutool.core.stream.CollectorUtil;
import cn.hutool.core.util.ArrayUtil;
import cn.hutool.core.util.JdkUtil;
import cn.hutool.core.util.ReflectUtil;
import cn.hutool.core.util.StrUtil;
@ -1459,30 +1460,35 @@ public class MapUtil {
*/
public static <K, V> Map.Entry<K, V> entry(K key, V value, boolean isImmutable) {
return isImmutable ?
new AbstractMap.SimpleImmutableEntry<>(key, value) :
new AbstractMap.SimpleEntry<>(key, value);
new AbstractMap.SimpleImmutableEntry<>(key, value) :
new AbstractMap.SimpleEntry<>(key, value);
}
/**
* 如果 key 对应的 value 不存在则使用获取 mappingFunction 重新计算后的值并保存为该 key value否则返回 value<br>
* 方法来自Dubbo解决使用ConcurrentHashMap.computeIfAbsent导致的死循环问题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.
* This class should be removed once we drop Java 8 support.<br>
* 参考https://github.com/apache/dubbo/blob/3.2/dubbo-common/src/main/java/org/apache/dubbo/common/utils/ConcurrentHashMapUtils.java
*
* @param <K> 键类型
* @param <V> 值类型
* @param map Map
* @param key
* @param mappingFunction 值不存在时值的生成函数
* @see <a href="https://bugs.openjdk.java.net/browse/JDK-8161372">https://bugs.openjdk.java.net/browse/JDK-8161372</a>
* @return
* @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<? super K, ? extends V> mappingFunction) {
V value = map.get(key);
if (null == value) {
map.putIfAbsent(key, mappingFunction.apply(key));
value = map.get(key);
if (JdkUtil.IS_JDK8) {
V value = map.get(key);
if (null == value) {
//map.putIfAbsent(key, mappingFunction.apply(key));
value = map.computeIfAbsent(key, mappingFunction);
}
return value;
} else {
return map.computeIfAbsent(key, mappingFunction);
}
return value;
}
}

View File

@ -0,0 +1,86 @@
/*
* Copyright (c) 2023 looly(loolly@aliyun.com)
* Hutool is licensed under Mulan PSL v2.
* You can use this software according to the terms and conditions of the Mulan PSL v2.
* You may obtain a copy of Mulan PSL v2 at:
* http://license.coscl.org.cn/MulanPSL2
* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
* See the Mulan PSL v2 for more details.
*/
package cn.hutool.core.util;
/**
* JDK相关工具类包括判断JDK版本等<br>
* 工具部分方法来自fastjson2的JDKUtils
*
* @author fastjson, looly
*/
public class JdkUtil {
/**
* JDK版本
*/
public static final int JVM_VERSION;
/**
* 是否JDK8<br>
* 由于Hutool基于JDK8编译当使用JDK版本低于8时不支持
*/
public static final boolean IS_JDK8;
/**
* 是否大于等于JDK17
*/
public static final boolean IS_AT_LEAST_JDK17;
/**
* 是否Android环境
*/
public static final boolean IS_ANDROID;
static {
// JVM版本
JVM_VERSION = _getJvmVersion();
IS_JDK8 = 8 == JVM_VERSION;
IS_AT_LEAST_JDK17 = JVM_VERSION >= 17;
// JVM名称
final String jvmName = _getJvmName();
IS_ANDROID = jvmName.equals("Dalvik");
}
/**
* 获取JVM名称
*
* @return JVM名称
*/
private static String _getJvmName() {
return System.getProperty("java.vm.name");
}
/**
* 根据{@code java.specification.version}属性值获取版本号
*
* @return 版本号
*/
private static int _getJvmVersion() {
int jvmVersion = -1;
try{
String javaSpecVer = System.getProperty("java.specification.version");
if (StrUtil.isNotBlank(javaSpecVer)) {
if (javaSpecVer.startsWith("1.")) {
javaSpecVer = javaSpecVer.substring(2);
}
if (javaSpecVer.indexOf('.') == -1) {
jvmVersion = Integer.parseInt(javaSpecVer);
}
}
} catch (Throwable ignore){
// 默认JDK8
jvmVersion = 8;
}
return jvmVersion;
}
}

View File

@ -1,6 +1,6 @@
package cn.hutool.http.ssl;
import cn.hutool.core.util.StrUtil;
import cn.hutool.core.util.JdkUtil;
import javax.net.ssl.SSLSocketFactory;
@ -22,7 +22,7 @@ public class DefaultSSLInfo {
static {
TRUST_ANY_HOSTNAME_VERIFIER = new TrustAnyHostnameVerifier();
if (StrUtil.equalsIgnoreCase("dalvik", System.getProperty("java.vm.name"))) {
if (JdkUtil.IS_ANDROID) {
// 兼容android低版本SSL连接
DEFAULT_SSF = new AndroidSupportSSLFactory();
} else {