add SafeConcurrentHashMap

This commit is contained in:
Looly 2022-09-15 10:36:20 +08:00
parent cf0fc45080
commit 3b5ba16c93
41 changed files with 176 additions and 104 deletions

View File

@ -1,6 +1,5 @@
package cn.hutool.core.annotation;
import cn.hutool.core.map.MapUtil;
import cn.hutool.core.map.WeakConcurrentMap;
import cn.hutool.core.util.ArrayUtil;
import cn.hutool.core.util.ObjUtil;
@ -495,7 +494,7 @@ public class AnnotatedElementUtil {
* @return {@link MetaAnnotatedElement}实例
*/
private static MetaAnnotatedElement<ResolvedAnnotationMapping> getResolvedMetaElementCache(final AnnotatedElement element) {
return MapUtil.computeIfAbsent(RESOLVED_ELEMENT_CACHE, element, ele -> MetaAnnotatedElement.create(
return RESOLVED_ELEMENT_CACHE.computeIfAbsent(element, ele -> MetaAnnotatedElement.create(
element, (source, annotation) -> ResolvedAnnotationMapping.create(source, annotation, true)
));
}
@ -507,7 +506,7 @@ public class AnnotatedElementUtil {
* @return {@link MetaAnnotatedElement}实例
*/
private static MetaAnnotatedElement<GenericAnnotationMapping> getMetaElementCache(final AnnotatedElement element) {
return MapUtil.computeIfAbsent(ELEMENT_CACHE, element, ele -> MetaAnnotatedElement.create(
return ELEMENT_CACHE.computeIfAbsent(element, ele -> MetaAnnotatedElement.create(
element, (source, annotation) -> GenericAnnotationMapping.create(annotation, Objects.isNull(source))
));
}

View File

@ -1,5 +1,6 @@
package cn.hutool.core.annotation;
import cn.hutool.core.map.SafeConcurrentHashMap;
import cn.hutool.core.reflect.MethodUtil;
import cn.hutool.core.text.CharSequenceUtil;
@ -11,7 +12,6 @@ import java.util.HashMap;
import java.util.Map;
import java.util.Objects;
import java.util.Optional;
import java.util.concurrent.ConcurrentHashMap;
import java.util.function.BiFunction;
import java.util.stream.Collectors;
import java.util.stream.Stream;
@ -80,7 +80,7 @@ public final class AnnotationMappingProxy<T extends Annotation> implements Invoc
private AnnotationMappingProxy(final AnnotationMapping<T> annotation) {
int methodCount = annotation.getAttributes().length;
this.methods = new HashMap<>(methodCount + 5);
this.valueCache = new ConcurrentHashMap<>(methodCount);
this.valueCache = new SafeConcurrentHashMap<>(methodCount);
this.mapping = annotation;
loadMethods();
}

View File

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

View File

@ -4,14 +4,13 @@ import cn.hutool.core.collection.iter.TransIter;
import cn.hutool.core.lang.func.SerSupplier;
import cn.hutool.core.lang.mutable.Mutable;
import cn.hutool.core.lang.mutable.MutableObj;
import cn.hutool.core.map.MapUtil;
import cn.hutool.core.map.SafeConcurrentHashMap;
import cn.hutool.core.map.WeakConcurrentMap;
import java.io.Serializable;
import java.util.Iterator;
import java.util.Map;
import java.util.WeakHashMap;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReadWriteLock;
import java.util.concurrent.locks.ReentrantLock;
@ -37,7 +36,7 @@ public class SimpleCache<K, V> implements Iterable<Map.Entry<K, V>>, Serializabl
/**
* 写的时候每个key一把锁降低锁的粒度
*/
protected final Map<K, Lock> keyLockMap = new ConcurrentHashMap<>();
protected final Map<K, Lock> keyLockMap = new SafeConcurrentHashMap<>();
/**
* 构造默认使用{@link WeakHashMap}实现缓存自动清理
@ -102,7 +101,7 @@ public class SimpleCache<K, V> implements Iterable<Map.Entry<K, V>>, Serializabl
}
if (null == v && null != supplier) {
//每个key单独获取一把锁降低锁的粒度提高并发能力see pr#1385@Github
final Lock keyLock = MapUtil.computeIfAbsent(this.keyLockMap, key, k -> new ReentrantLock());
final Lock keyLock = this.keyLockMap.computeIfAbsent(key, k -> new ReentrantLock());
keyLock.lock();
try {
// 双重检查防止在竞争锁的过程中已经有其它线程写入

View File

@ -5,11 +5,11 @@ import cn.hutool.core.cache.CacheListener;
import cn.hutool.core.lang.func.SerSupplier;
import cn.hutool.core.lang.mutable.Mutable;
import cn.hutool.core.lang.mutable.MutableObj;
import cn.hutool.core.map.SafeConcurrentHashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.atomic.LongAdder;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
@ -35,7 +35,7 @@ public abstract class AbstractCache<K, V> implements Cache<K, V> {
/**
* 写的时候每个key一把锁降低锁的粒度
*/
protected final Map<K, Lock> keyLockMap = new ConcurrentHashMap<>();
protected final Map<K, Lock> keyLockMap = new SafeConcurrentHashMap<>();
/**
* 返回缓存容量{@code 0}表示无大小限制

View File

@ -4,6 +4,7 @@ import cn.hutool.core.convert.BasicType;
import cn.hutool.core.exceptions.UtilException;
import cn.hutool.core.lang.Assert;
import cn.hutool.core.map.MapUtil;
import cn.hutool.core.map.SafeConcurrentHashMap;
import cn.hutool.core.map.WeakConcurrentMap;
import cn.hutool.core.text.CharPool;
import cn.hutool.core.text.StrUtil;
@ -15,7 +16,6 @@ import java.security.PrivilegedAction;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
/**
* {@link ClassLoader}工具类
@ -49,7 +49,7 @@ public class ClassLoaderUtil {
/**
* 原始类型名和其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 SafeConcurrentHashMap<>(32);
private static final Map<Map.Entry<String, ClassLoader>, Class<?>> CLASS_CACHE = new WeakConcurrentMap<>();
static {
@ -203,7 +203,7 @@ public class ClassLoaderUtil {
if (clazz == null) {
final String finalName = name;
final ClassLoader finalClassLoader = classLoader;
clazz = MapUtil.computeIfAbsent(CLASS_CACHE, MapUtil.entry(name, classLoader), (key) -> doLoadClass(finalName, finalClassLoader, isInitialized));
clazz = CLASS_CACHE.computeIfAbsent(MapUtil.entry(name, classLoader), (key) -> doLoadClass(finalName, finalClassLoader, isInitialized));
}
return (Class<T>) clazz;
}

View File

@ -1,10 +1,11 @@
package cn.hutool.core.collection;
import cn.hutool.core.map.SafeConcurrentHashMap;
import java.util.Collection;
import java.util.concurrent.ConcurrentHashMap;
/**
* 通过{@link ConcurrentHashMap}实现的线程安全HashSet
* 通过{@link SafeConcurrentHashMap}实现的线程安全HashSet
*
* @author Looly
*
@ -20,7 +21,7 @@ public class ConcurrentHashSet<E> extends SetFromMap<E> {
* 触发因子为默认的0.75
*/
public ConcurrentHashSet() {
super(new ConcurrentHashMap<>());
super(new SafeConcurrentHashMap<>());
}
/**
@ -30,7 +31,7 @@ public class ConcurrentHashSet<E> extends SetFromMap<E> {
* @param initialCapacity 初始大小
*/
public ConcurrentHashSet(final int initialCapacity) {
super(new ConcurrentHashMap<>(initialCapacity));
super(new SafeConcurrentHashMap<>(initialCapacity));
}
/**
@ -40,7 +41,7 @@ public class ConcurrentHashSet<E> extends SetFromMap<E> {
* @param loadFactor 加载因子此参数决定数据增长时触发的百分比
*/
public ConcurrentHashSet(final int initialCapacity, final float loadFactor) {
super(new ConcurrentHashMap<>(initialCapacity, loadFactor));
super(new SafeConcurrentHashMap<>(initialCapacity, loadFactor));
}
/**
@ -51,7 +52,7 @@ public class ConcurrentHashSet<E> extends SetFromMap<E> {
* @param concurrencyLevel 线程并发度
*/
public ConcurrentHashSet(final int initialCapacity, final float loadFactor, final int concurrencyLevel) {
super(new ConcurrentHashMap<>(initialCapacity, loadFactor, concurrencyLevel));
super(new SafeConcurrentHashMap<>(initialCapacity, loadFactor, concurrencyLevel));
}
/**
@ -59,7 +60,7 @@ public class ConcurrentHashSet<E> extends SetFromMap<E> {
* @param iter {@link Iterable}
*/
public ConcurrentHashSet(final Iterable<E> iter) {
super(iter instanceof Collection ? new ConcurrentHashMap<>((int)(((Collection<E>)iter).size() / 0.75f)) : new ConcurrentHashMap<>());
super(iter instanceof Collection ? new SafeConcurrentHashMap<>(((Collection<E>)iter).size()) : new SafeConcurrentHashMap<>());
if(iter instanceof Collection) {
this.addAll((Collection<E>)iter);
}else {

View File

@ -1,7 +1,8 @@
package cn.hutool.core.convert;
import cn.hutool.core.map.SafeConcurrentHashMap;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
/**
* 基本变量类型的枚举<br>
@ -12,9 +13,9 @@ public enum BasicType {
BYTE, SHORT, INT, INTEGER, LONG, DOUBLE, FLOAT, BOOLEAN, CHAR, CHARACTER, STRING;
/** 包装类型为Key原始类型为Value例如 Integer.class =》 int.class. */
public static final Map<Class<?>, Class<?>> WRAPPER_PRIMITIVE_MAP = new ConcurrentHashMap<>(8);
public static final Map<Class<?>, Class<?>> WRAPPER_PRIMITIVE_MAP = new SafeConcurrentHashMap<>(8);
/** 原始类型为Key包装类型为Value例如 int.class =》 Integer.class. */
public static final Map<Class<?>, Class<?>> PRIMITIVE_WRAPPER_MAP = new ConcurrentHashMap<>(8);
public static final Map<Class<?>, Class<?>> PRIMITIVE_WRAPPER_MAP = new SafeConcurrentHashMap<>(8);
static {
WRAPPER_PRIMITIVE_MAP.put(Boolean.class, boolean.class);

View File

@ -29,6 +29,7 @@ import cn.hutool.core.convert.impl.XMLGregorianCalendarConverter;
import cn.hutool.core.convert.impl.ZoneIdConverter;
import cn.hutool.core.date.DateTime;
import cn.hutool.core.lang.Opt;
import cn.hutool.core.map.SafeConcurrentHashMap;
import javax.xml.datatype.XMLGregorianCalendar;
import java.io.Serializable;
@ -60,7 +61,6 @@ import java.util.Map;
import java.util.Optional;
import java.util.TimeZone;
import java.util.UUID;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicIntegerArray;
import java.util.concurrent.atomic.AtomicLongArray;
@ -176,7 +176,7 @@ public class RegisterConverter implements Converter, Serializable {
if (null == customConverterMap) {
synchronized (this) {
if (null == customConverterMap) {
customConverterMap = new ConcurrentHashMap<>();
customConverterMap = new SafeConcurrentHashMap<>();
}
}
}
@ -188,7 +188,7 @@ public class RegisterConverter implements Converter, Serializable {
* 注册默认转换器
*/
private void registerDefault() {
defaultConverterMap = new ConcurrentHashMap<>();
defaultConverterMap = new SafeConcurrentHashMap<>(64);
// 包装类转换器
defaultConverterMap.put(Character.class, new CharacterConverter());

View File

@ -118,7 +118,7 @@ public class EnumConverter extends AbstractConverter {
* @return 转换方法mapkey为方法参数类型value为方法
*/
private static Map<Class<?>, Method> getMethodMap(final Class<?> enumClass) {
return MapUtil.computeIfAbsent(VALUE_OF_METHOD_CACHE, enumClass, (key) -> Arrays.stream(enumClass.getMethods())
return VALUE_OF_METHOD_CACHE.computeIfAbsent(enumClass, (key) -> Arrays.stream(enumClass.getMethods())
.filter(ModifierUtil::isStatic)
.filter(m -> m.getReturnType() == enumClass)
.filter(m -> m.getParameterCount() == 1)

View File

@ -2,6 +2,7 @@ package cn.hutool.core.date.format;
import cn.hutool.core.date.DateException;
import cn.hutool.core.date.format.parser.FastDateParser;
import cn.hutool.core.map.SafeConcurrentHashMap;
import java.io.IOException;
import java.io.ObjectInputStream;
@ -12,7 +13,6 @@ import java.util.Date;
import java.util.List;
import java.util.Locale;
import java.util.TimeZone;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
/**
@ -1050,7 +1050,7 @@ public class FastDatePrinter extends SimpleDateBasic implements DatePrinter {
// -----------------------------------------------------------------------
private static final ConcurrentMap<TimeZoneDisplayKey, String> C_TIME_ZONE_DISPLAY_CACHE = new ConcurrentHashMap<>(7);
private static final ConcurrentMap<TimeZoneDisplayKey, String> C_TIME_ZONE_DISPLAY_CACHE = new SafeConcurrentHashMap<>(7);
/**
* <p>

View File

@ -2,13 +2,13 @@ package cn.hutool.core.date.format;
import cn.hutool.core.lang.Assert;
import cn.hutool.core.lang.Tuple;
import cn.hutool.core.map.SafeConcurrentHashMap;
import java.text.DateFormat;
import java.text.Format;
import java.text.SimpleDateFormat;
import java.util.Locale;
import java.util.TimeZone;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
/**
@ -24,9 +24,9 @@ abstract class FormatCache<F extends Format> {
*/
static final int NONE = -1;
private final ConcurrentMap<Tuple, F> cInstanceCache = new ConcurrentHashMap<>(7);
private final ConcurrentMap<Tuple, F> cInstanceCache = new SafeConcurrentHashMap<>(7);
private static final ConcurrentMap<Tuple, String> C_DATE_TIME_INSTANCE_CACHE = new ConcurrentHashMap<>(7);
private static final ConcurrentMap<Tuple, String> C_DATE_TIME_INSTANCE_CACHE = new SafeConcurrentHashMap<>(7);
/**
* 使用默认的patterntimezone和locale获得缓存中的实例

View File

@ -2,11 +2,11 @@ package cn.hutool.core.date.format;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.lang.Assert;
import cn.hutool.core.map.SafeConcurrentHashMap;
import java.time.temporal.TemporalAccessor;
import java.util.Date;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.function.Function;
/**
@ -25,8 +25,8 @@ public class GlobalCustomFormat {
private static final Map<CharSequence, Function<CharSequence, Date>> parserMap;
static {
formatterMap = new ConcurrentHashMap<>();
parserMap = new ConcurrentHashMap<>();
formatterMap = new SafeConcurrentHashMap<>();
parserMap = new SafeConcurrentHashMap<>();
// Hutool预设的几种自定义格式
putFormatter(FORMAT_SECONDS, (date) -> String.valueOf(Math.floorDiv(date.getTime(), 1000)));

View File

@ -3,6 +3,7 @@ package cn.hutool.core.date.format.parser;
import cn.hutool.core.date.format.FastDateFormat;
import cn.hutool.core.date.format.FastDatePrinter;
import cn.hutool.core.date.format.SimpleDateBasic;
import cn.hutool.core.map.SafeConcurrentHashMap;
import java.io.IOException;
import java.io.ObjectInputStream;
@ -22,7 +23,6 @@ import java.util.Objects;
import java.util.Set;
import java.util.TimeZone;
import java.util.TreeSet;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
@ -453,7 +453,7 @@ public class FastDateParser extends SimpleDateBasic implements PositionDateParse
private static ConcurrentMap<Locale, Strategy> getCache(final int field) {
synchronized (CACHES) {
if (CACHES[field] == null) {
CACHES[field] = new ConcurrentHashMap<>(3);
CACHES[field] = new SafeConcurrentHashMap<>(3);
}
return CACHES[field];
}

View File

@ -2,13 +2,12 @@ package cn.hutool.core.lang;
import cn.hutool.core.classloader.ClassLoaderUtil;
import cn.hutool.core.lang.func.SerSupplier;
import cn.hutool.core.map.MapUtil;
import cn.hutool.core.map.SafeConcurrentHashMap;
import cn.hutool.core.reflect.ConstructorUtil;
import cn.hutool.core.text.StrUtil;
import cn.hutool.core.util.ArrayUtil;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.stream.Collectors;
/**
@ -19,7 +18,7 @@ import java.util.stream.Collectors;
*/
public final class Singleton {
private static final ConcurrentHashMap<String, Object> POOL = new ConcurrentHashMap<>();
private static final SafeConcurrentHashMap<String, Object> POOL = new SafeConcurrentHashMap<>();
private Singleton() {
}
@ -53,7 +52,7 @@ public final class Singleton {
*/
@SuppressWarnings("unchecked")
public static <T> T get(final String key, final SerSupplier<T> supplier) {
return (T) MapUtil.computeIfAbsent(POOL, key, (k)-> supplier.get());
return (T) POOL.computeIfAbsent(key, (k)-> supplier.get());
}
/**

View File

@ -4,7 +4,6 @@ import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.classloader.ClassLoaderUtil;
import cn.hutool.core.exceptions.UtilException;
import cn.hutool.core.lang.Opt;
import cn.hutool.core.map.MapUtil;
import cn.hutool.core.map.WeakConcurrentMap;
import cn.hutool.core.reflect.MethodUtil;
import cn.hutool.core.reflect.ReflectUtil;
@ -74,7 +73,7 @@ public class LambdaUtil {
* @return 返回解析后的结果
*/
public static <T extends Serializable> LambdaInfo resolve(final T func) {
return MapUtil.computeIfAbsent(CACHE, func.getClass().getName(), (key) -> {
return CACHE.computeIfAbsent(func.getClass().getName(), (key) -> {
final SerializedLambda serializedLambda = _resolve(func);
final String methodName = serializedLambda.getImplMethodName();
final Class<?> implClass;

View File

@ -1,6 +1,5 @@
package cn.hutool.core.lang.intern;
import cn.hutool.core.map.MapUtil;
import cn.hutool.core.map.WeakConcurrentMap;
/**
@ -18,6 +17,6 @@ public class WeakInterner<T> implements Interner<T>{
if(null == sample){
return null;
}
return MapUtil.computeIfAbsent(cache, sample, (key)->sample);
return cache.computeIfAbsent(sample, (key)->sample);
}
}

View File

@ -1265,16 +1265,16 @@ public class MapUtil extends MapGetUtil {
}
/**
* 方法来自Dubbo解决使用ConcurrentHashMap.computeIfAbsent导致的死循环问题<br>
* issues#2349<br>
* 如果 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.
*
* @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(final Map<K, V> map, final K key, final Function<K, V> mappingFunction) {
public static <K, V> V computeIfAbsent(final Map<K, V> map, final K key, final Function<? super K, ? extends V> mappingFunction) {
V value = map.get(key);
if(null == value){
if (null == value) {
map.putIfAbsent(key, mappingFunction.apply(key));
value = map.get(key);
}

View File

@ -133,7 +133,7 @@ public class ReferenceConcurrentMap<K, V> implements ConcurrentMap<K, V>, Iterab
@Override
public V computeIfAbsent(final K key, final Function<? super K, ? extends V> mappingFunction) {
this.purgeStaleKeys();
return MapUtil.computeIfAbsent(this.raw, ofKey(key, this.lastQueue), kWeakKey -> mappingFunction.apply(key));
return this.raw.computeIfAbsent(ofKey(key, this.lastQueue), kWeakKey -> mappingFunction.apply(key));
}
@Override

View File

@ -0,0 +1,74 @@
package cn.hutool.core.map;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.function.Function;
/**
* 安全的ConcurrentHashMap实现<br>
* 此类用于解决在JDK8中调用{@link ConcurrentHashMap#computeIfAbsent(Object, Function)}可能造成的死循环问题<br>
* 方法来自Dubboissues#2349<br>
* <p>
* 相关bug见@see <a href="https://bugs.openjdk.java.net/browse/JDK-8161372">https://bugs.openjdk.java.net/browse/JDK-8161372</a>
*
* @param <K> 键类型
* @param <V> 值类型
*/
public class SafeConcurrentHashMap<K, V> extends ConcurrentHashMap<K, V> {
private static final long serialVersionUID = 1L;
// region == 构造 ==
/**
* 构造默认初始大小16
*/
public SafeConcurrentHashMap() {
super();
}
/**
* 构造
*
* @param initialCapacity 预估初始大小
*/
public SafeConcurrentHashMap(int initialCapacity) {
super(initialCapacity);
}
/**
* 构造
*
* @param m 初始键值对
*/
public SafeConcurrentHashMap(Map<? extends K, ? extends V> m) {
super(m);
}
/**
* 构造
*
* @param initialCapacity 初始容量
* @param loadFactor 增长系数
*/
public SafeConcurrentHashMap(int initialCapacity, float loadFactor) {
super(initialCapacity, loadFactor);
}
/**
* 构造
*
* @param initialCapacity 初始容量
* @param loadFactor 增长系数
* @param concurrencyLevel 并发级别即Segment的个数
*/
public SafeConcurrentHashMap(int initialCapacity,
float loadFactor, int concurrencyLevel) {
super(initialCapacity, loadFactor, concurrencyLevel);
}
// endregion == 构造 ==
@Override
public V computeIfAbsent(K key, Function<? super K, ? extends V> mappingFunction) {
return MapUtil.computeIfAbsent(this, key, mappingFunction);
}
}

View File

@ -3,7 +3,6 @@ package cn.hutool.core.map;
import cn.hutool.core.util.ReferenceUtil;
import java.lang.ref.Reference;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
/**
@ -16,12 +15,13 @@ import java.util.concurrent.ConcurrentMap;
* @since 5.8.0
*/
public class WeakConcurrentMap<K, V> extends ReferenceConcurrentMap<K, V> {
private static final long serialVersionUID = 1L;
/**
* 构造
*/
public WeakConcurrentMap() {
this(new ConcurrentHashMap<>());
this(new SafeConcurrentHashMap<>());
}
/**

View File

@ -1,7 +1,6 @@
package cn.hutool.core.reflect;
import cn.hutool.core.convert.Convert;
import cn.hutool.core.map.MapUtil;
import cn.hutool.core.map.WeakConcurrentMap;
import java.lang.reflect.ParameterizedType;
@ -27,7 +26,7 @@ public class ActualTypeMapperPool {
* @return 泛型对应关系Map
*/
public static Map<Type, Type> get(final Type type) {
return MapUtil.computeIfAbsent(CACHE, type, (key) -> createTypeMap(type));
return CACHE.computeIfAbsent(type, (key) -> createTypeMap(type));
}
/**

View File

@ -2,7 +2,6 @@ package cn.hutool.core.reflect;
import cn.hutool.core.exceptions.UtilException;
import cn.hutool.core.lang.Assert;
import cn.hutool.core.map.MapUtil;
import cn.hutool.core.map.WeakConcurrentMap;
import cn.hutool.core.util.ArrayUtil;
@ -65,7 +64,7 @@ public class ConstructorUtil {
@SuppressWarnings("unchecked")
public static <T> Constructor<T>[] getConstructors(final Class<T> beanClass) throws SecurityException {
Assert.notNull(beanClass);
return (Constructor<T>[]) MapUtil.computeIfAbsent(CONSTRUCTORS_CACHE, beanClass, (key) -> getConstructorsDirectly(beanClass));
return (Constructor<T>[]) CONSTRUCTORS_CACHE.computeIfAbsent(beanClass, (key) -> getConstructorsDirectly(beanClass));
}
/**

View File

@ -116,7 +116,7 @@ public class FieldUtil {
*/
public static Field[] getFields(final Class<?> beanClass) throws SecurityException {
Assert.notNull(beanClass);
return MapUtil.computeIfAbsent(FIELDS_CACHE, beanClass, (key) -> getFieldsDirectly(beanClass, true));
return FIELDS_CACHE.computeIfAbsent(beanClass, (key) -> getFieldsDirectly(beanClass, true));
}

View File

@ -9,7 +9,6 @@ import cn.hutool.core.exceptions.InvocationTargetRuntimeException;
import cn.hutool.core.exceptions.UtilException;
import cn.hutool.core.lang.Assert;
import cn.hutool.core.lang.Singleton;
import cn.hutool.core.map.MapUtil;
import cn.hutool.core.map.WeakConcurrentMap;
import cn.hutool.core.text.StrUtil;
import cn.hutool.core.util.ArrayUtil;
@ -320,7 +319,7 @@ public class MethodUtil {
*/
public static Method[] getMethods(final Class<?> beanClass) throws SecurityException {
Assert.notNull(beanClass);
return MapUtil.computeIfAbsent(METHODS_CACHE, beanClass,
return METHODS_CACHE.computeIfAbsent(beanClass,
(key) -> getMethodsDirectly(beanClass, true, true));
}

View File

@ -1,6 +1,5 @@
package cn.hutool.core.regex;
import cn.hutool.core.map.MapUtil;
import cn.hutool.core.map.WeakConcurrentMap;
import java.util.regex.Pattern;
@ -198,7 +197,7 @@ public class PatternPool {
*/
public static Pattern get(final String regex, final int flags) {
final RegexWithFlag regexWithFlag = new RegexWithFlag(regex, flags);
return MapUtil.computeIfAbsent(POOL, regexWithFlag, (key) -> Pattern.compile(regex, flags));
return POOL.computeIfAbsent(regexWithFlag, (key) -> Pattern.compile(regex, flags));
}
/**

View File

@ -6,13 +6,22 @@ import cn.hutool.core.lang.Console;
import cn.hutool.core.lang.mutable.MutableInt;
import cn.hutool.core.lang.mutable.MutableObj;
import cn.hutool.core.map.MapUtil;
import cn.hutool.core.map.SafeConcurrentHashMap;
import cn.hutool.core.util.ArrayUtil;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.function.*;
import java.util.function.BiConsumer;
import java.util.function.BiFunction;
import java.util.function.BiPredicate;
import java.util.function.Consumer;
import java.util.function.Function;
import java.util.function.Predicate;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import java.util.stream.StreamSupport;
@ -221,7 +230,7 @@ public interface TransformableWrappedStream<T, S extends TransformableWrappedStr
default <F> EasyStream<T> distinct(final Function<? super T, F> keyExtractor) {
Objects.requireNonNull(keyExtractor);
if (isParallel()) {
final ConcurrentHashMap<F, Boolean> exists = MapUtil.newConcurrentHashMap();
final SafeConcurrentHashMap<F, Boolean> exists = new SafeConcurrentHashMap<>();
// 标记是否出现过null值用于保留第一个出现的null
// 由于ConcurrentHashMap的key不能为null所以用此变量来标记
final AtomicBoolean hasNull = new AtomicBoolean(false);

View File

@ -1,6 +1,7 @@
package cn.hutool.core.text;
import cn.hutool.core.map.SafeConcurrentHashMap;
import cn.hutool.core.text.split.SplitUtil;
import java.util.ArrayList;
@ -8,7 +9,6 @@ import java.util.Comparator;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
@ -62,9 +62,9 @@ public class AntPathMatcher {
private volatile Boolean cachePatterns;
private final Map<String, String[]> tokenizedPatternCache = new ConcurrentHashMap<>(256);
private final Map<String, String[]> tokenizedPatternCache = new SafeConcurrentHashMap<>(256);
private final Map<String, AntPathStringMatcher> stringMatcherCache = new ConcurrentHashMap<>(256);
private final Map<String, AntPathStringMatcher> stringMatcherCache = new SafeConcurrentHashMap<>(256);
/**

View File

@ -1,11 +1,11 @@
package cn.hutool.core.util;
import cn.hutool.core.map.SafeConcurrentHashMap;
import cn.hutool.core.regex.PatternPool;
import cn.hutool.core.regex.ReUtil;
import cn.hutool.core.text.StrUtil;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.regex.Pattern;
/**
@ -38,7 +38,7 @@ public class CreditCodeUtil {
private static final Map<Character, Integer> CODE_INDEX_MAP;
static {
CODE_INDEX_MAP = new ConcurrentHashMap<>();
CODE_INDEX_MAP = new SafeConcurrentHashMap<>();
for (int i = 0; i < BASE_CODE_ARRAY.length; i++) {
CODE_INDEX_MAP.put(BASE_CODE_ARRAY[i], i);
}

View File

@ -1,6 +1,7 @@
package cn.hutool.db.dialect;
import cn.hutool.core.classloader.ClassLoaderUtil;
import cn.hutool.core.map.SafeConcurrentHashMap;
import cn.hutool.core.regex.ReUtil;
import cn.hutool.core.text.StrUtil;
import cn.hutool.db.dialect.impl.AnsiSqlDialect;
@ -16,7 +17,6 @@ import cn.hutool.log.StaticLog;
import javax.sql.DataSource;
import java.sql.Connection;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
/**
* 方言工厂类
@ -26,7 +26,7 @@ import java.util.concurrent.ConcurrentHashMap;
*/
public class DialectFactory implements DriverNamePool{
private static final Map<DataSource, Dialect> DIALECT_POOL = new ConcurrentHashMap<>();
private static final Map<DataSource, Dialect> DIALECT_POOL = new SafeConcurrentHashMap<>();
private DialectFactory() {
}
@ -170,11 +170,7 @@ public class DialectFactory implements DriverNamePool{
// 数据源作为锁的意义在于不同数据源不会导致阻塞相同数据源获取方言时可保证互斥
//noinspection SynchronizationOnLocalVariableOrMethodParameter
synchronized (ds) {
dialect = DIALECT_POOL.get(ds);
if(null == dialect) {
dialect = newDialect(ds);
DIALECT_POOL.put(ds, dialect);
}
dialect = DIALECT_POOL.computeIfAbsent(ds, DialectFactory::newDialect);
}
}
return dialect;

View File

@ -2,6 +2,7 @@ package cn.hutool.db.ds;
import cn.hutool.core.lang.Assert;
import cn.hutool.core.map.MapUtil;
import cn.hutool.core.map.SafeConcurrentHashMap;
import cn.hutool.core.text.StrUtil;
import cn.hutool.db.DbRuntimeException;
import cn.hutool.db.DbUtil;
@ -12,7 +13,6 @@ import cn.hutool.setting.Setting;
import javax.sql.DataSource;
import java.util.Collection;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
/**
* 抽象数据源工厂<br>
@ -54,7 +54,7 @@ public abstract class AbstractDSFactory extends DSFactory {
DbUtil.setShowSqlGlobal(setting);
this.setting = setting;
this.dsMap = new ConcurrentHashMap<>();
this.dsMap = new SafeConcurrentHashMap<>();
}
/**

View File

@ -1,7 +1,7 @@
package cn.hutool.db.meta;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
/**
* JDBC中字段类型枚举
@ -63,7 +63,8 @@ public enum JdbcType {
this.typeCode = code;
}
private static final Map<Integer, JdbcType> CODE_MAP = new ConcurrentHashMap<>(100, 1);
// 此处无写操作使用HashMap没有线程安全问题
private static final Map<Integer, JdbcType> CODE_MAP = new HashMap<>(128, 1);
static {
for (final JdbcType type : JdbcType.values()) {
CODE_MAP.put(type.typeCode, type);
@ -74,7 +75,7 @@ public enum JdbcType {
* 通过{@link java.sql.Types}中对应int值找到enum值
*
* @param code Jdbc type值
* @return {@link JdbcType}
* @return {@code JdbcType}
*/
public static JdbcType valueOf(final int code) {
return CODE_MAP.get(code);

View File

@ -1,6 +1,5 @@
package cn.hutool.extra.cglib;
import cn.hutool.core.map.MapUtil;
import cn.hutool.core.map.WeakConcurrentMap;
import cn.hutool.core.text.StrUtil;
import net.sf.cglib.beans.BeanCopier;
@ -44,7 +43,7 @@ public enum BeanCopierCache {
*/
public BeanCopier get(final Class<?> srcClass, final Class<?> targetClass, final boolean useConverter) {
final String key = genKey(srcClass, targetClass, useConverter);
return MapUtil.computeIfAbsent(cache, key, (k) -> BeanCopier.create(srcClass, targetClass, useConverter));
return cache.computeIfAbsent(key, (k) -> BeanCopier.create(srcClass, targetClass, useConverter));
}
/**

View File

@ -1,7 +1,6 @@
package cn.hutool.extra.script;
import cn.hutool.core.exceptions.UtilException;
import cn.hutool.core.map.MapUtil;
import cn.hutool.core.map.WeakConcurrentMap;
import cn.hutool.core.text.StrUtil;
@ -31,7 +30,7 @@ public class ScriptUtil {
* @return {@link ScriptEngine} 实例
*/
public static ScriptEngine getScript(final String nameOrExtOrMime) {
return MapUtil.computeIfAbsent(CACHE, nameOrExtOrMime, (key) -> createScript(nameOrExtOrMime));
return CACHE.computeIfAbsent(nameOrExtOrMime, (key) -> createScript(nameOrExtOrMime));
}
/**

View File

@ -1,6 +1,7 @@
package cn.hutool.http;
import cn.hutool.core.lang.Console;
import cn.hutool.core.map.SafeConcurrentHashMap;
import cn.hutool.core.util.CharUtil;
import java.util.ArrayList;
@ -8,7 +9,6 @@ import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
@ -61,8 +61,8 @@ public final class HTMLFilter {
private static final Pattern P_BOTH_ARROWS = Pattern.compile("<>");
// @xxx could grow large... maybe use sesat's ReferenceMap
private static final ConcurrentMap<String, Pattern> P_REMOVE_PAIR_BLANKS = new ConcurrentHashMap<>();
private static final ConcurrentMap<String, Pattern> P_REMOVE_SELF_BLANKS = new ConcurrentHashMap<>();
private static final ConcurrentMap<String, Pattern> P_REMOVE_PAIR_BLANKS = new SafeConcurrentHashMap<>();
private static final ConcurrentMap<String, Pattern> P_REMOVE_SELF_BLANKS = new SafeConcurrentHashMap<>();
/**
* set of allowed html elements, along with allowed attributes for each element

View File

@ -1,5 +1,6 @@
package cn.hutool.json.serialize;
import cn.hutool.core.map.SafeConcurrentHashMap;
import cn.hutool.json.JSON;
import java.lang.reflect.Type;
@ -22,8 +23,8 @@ public class GlobalSerializeMapping {
private static Map<Type, JSONDeserializer<?>> deserializerMap;
static {
serializerMap = new ConcurrentHashMap<>();
deserializerMap = new ConcurrentHashMap<>();
serializerMap = new SafeConcurrentHashMap<>();
deserializerMap = new SafeConcurrentHashMap<>();
final TemporalAccessorSerializer localDateSerializer = new TemporalAccessorSerializer(LocalDate.class);
serializerMap.put(LocalDate.class, localDateSerializer);

View File

@ -2,13 +2,13 @@ package cn.hutool.log;
import cn.hutool.core.io.resource.ResourceUtil;
import cn.hutool.core.lang.caller.CallerUtil;
import cn.hutool.core.map.SafeConcurrentHashMap;
import cn.hutool.core.util.ServiceLoaderUtil;
import cn.hutool.log.dialect.console.ConsoleLogFactory;
import cn.hutool.log.dialect.jdk.JdkLogFactory;
import java.net.URL;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
/**
* 日志工厂类
@ -33,7 +33,7 @@ public abstract class LogFactory {
*/
public LogFactory(final String name) {
this.name = name;
logCache = new ConcurrentHashMap<>();
logCache = new SafeConcurrentHashMap<>();
}
/**

View File

@ -9,6 +9,7 @@ import cn.hutool.core.io.IoUtil;
import cn.hutool.core.lang.Assert;
import cn.hutool.core.lang.id.IdUtil;
import cn.hutool.core.map.MapUtil;
import cn.hutool.core.map.SafeConcurrentHashMap;
import cn.hutool.core.map.TableMap;
import cn.hutool.core.map.multi.RowKeyTable;
import cn.hutool.core.map.multi.Table;
@ -44,7 +45,6 @@ import java.util.LinkedHashMap;
import java.util.Map;
import java.util.Set;
import java.util.TreeMap;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.atomic.AtomicInteger;
/**
@ -59,6 +59,7 @@ import java.util.concurrent.atomic.AtomicInteger;
* @author Looly
* @since 3.2.0
*/
@SuppressWarnings("resource")
public class ExcelWriter extends ExcelBase<ExcelWriter> {
/**
@ -938,7 +939,7 @@ public class ExcelWriter extends ExcelBase<ExcelWriter> {
*/
public ExcelWriter writeHeadRow(final Iterable<?> rowData) {
Assert.isFalse(this.isClosed, "ExcelWriter has been closed!");
this.headLocationCache = new ConcurrentHashMap<>();
this.headLocationCache = new SafeConcurrentHashMap<>();
final Row row = this.sheet.createRow(this.currentRow.getAndIncrement());
int i = 0;
Cell cell;

View File

@ -2,10 +2,10 @@ package cn.hutool.setting;
import cn.hutool.core.io.file.FileNameUtil;
import cn.hutool.core.io.resource.NoResourceException;
import cn.hutool.core.map.SafeConcurrentHashMap;
import cn.hutool.core.text.StrUtil;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
/**
* Setting工具类<br>
@ -17,7 +17,7 @@ public class SettingUtil {
/**
* 配置文件缓存
*/
private static final Map<String, Setting> SETTING_MAP = new ConcurrentHashMap<>();
private static final Map<String, Setting> SETTING_MAP = new SafeConcurrentHashMap<>();
/**
* 获取当前环境下的配置文件<br>

View File

@ -2,10 +2,10 @@ package cn.hutool.setting.dialect;
import cn.hutool.core.io.FileUtil;
import cn.hutool.core.io.resource.NoResourceException;
import cn.hutool.core.map.SafeConcurrentHashMap;
import cn.hutool.core.text.StrUtil;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
/**
* Props工具类<br>
@ -19,7 +19,7 @@ public class PropsUtil {
/**
* 配置文件缓存
*/
private static final Map<String, Props> propsMap = new ConcurrentHashMap<>();
private static final Map<String, Props> propsMap = new SafeConcurrentHashMap<>();
/**
* 获取当前环境下的配置文件<br>

View File

@ -1,13 +1,13 @@
package cn.hutool.setting.profile;
import cn.hutool.core.lang.Assert;
import cn.hutool.core.map.SafeConcurrentHashMap;
import cn.hutool.core.text.StrUtil;
import cn.hutool.setting.Setting;
import java.io.Serializable;
import java.nio.charset.Charset;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
/**
* Profile可以让我们定义一系列的配置信息然后指定其激活条件<br>
@ -36,7 +36,7 @@ public class Profile implements Serializable {
/** 是否使用变量 */
private boolean useVar;
/** 配置文件缓存 */
private final Map<String, Setting> settingMap = new ConcurrentHashMap<>();
private final Map<String, Setting> settingMap = new SafeConcurrentHashMap<>();
// -------------------------------------------------------------------------------- Constructor start
/**