增加SafeConcurrentHashMap

This commit is contained in:
Looly 2022-09-15 09:50:54 +08:00
parent 920fe44e50
commit 06fec1045c
31 changed files with 168 additions and 105 deletions

View File

@ -12,6 +12,7 @@
* 【core 】 新增AnsiColors(改自Spring Boot)、AnsiColorWrapper优化QrCodeUtilpr#778@Gitee
* 【core 】 TemplateUtil的实现类增加getRawEngine方法issues#2530@Github
* 【core 】 ImgUtil中颜色相关方法剥离到ColorUtil中
* 【core 】 增加SafeConcurrentHashMap
### 🐞Bug修复
* 【core 】 修复ObjectUtil.defaultIfXXX中NPE问题pr#2603@Github

View File

@ -5,11 +5,11 @@ import cn.hutool.cache.CacheListener;
import cn.hutool.core.lang.func.Func0;
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 SafeConcurrentHashMap<K, Lock> keyLockMap = new SafeConcurrentHashMap<>();
/**
* 返回缓存容量{@code 0}表示无大小限制

View File

@ -1,7 +1,6 @@
package cn.hutool.core.bean;
import cn.hutool.core.lang.func.Func0;
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(Class<?> beanClass, Func0<BeanDesc> supplier) {
return MapUtil.computeIfAbsent(bdCache, beanClass, (key)->supplier.callWithRuntimeException());
return bdCache.computeIfAbsent(beanClass, (key)->supplier.callWithRuntimeException());
}
/**

View File

@ -1,12 +1,13 @@
package cn.hutool.core.collection;
import cn.hutool.core.map.SafeConcurrentHashMap;
import java.util.AbstractSet;
import java.util.Collection;
import java.util.Iterator;
import java.util.concurrent.ConcurrentHashMap;
/**
* 通过{@link ConcurrentHashMap}实现的线程安全HashSet
* 通过{@link SafeConcurrentHashMap}实现的线程安全HashSet
*
* @author Looly
*
@ -18,7 +19,7 @@ public class ConcurrentHashSet<E> extends AbstractSet<E> implements java.io.Seri
/** 持有对象。如果值为此对象表示有数据,否则无数据 */
private static final Boolean PRESENT = true;
private final ConcurrentHashMap<E, Boolean> map;
private final SafeConcurrentHashMap<E, Boolean> map;
// ----------------------------------------------------------------------------------- Constructor start
/**
@ -26,7 +27,7 @@ public class ConcurrentHashSet<E> extends AbstractSet<E> implements java.io.Seri
* 触发因子为默认的0.75
*/
public ConcurrentHashSet() {
map = new ConcurrentHashMap<>();
map = new SafeConcurrentHashMap<>();
}
/**
@ -36,7 +37,7 @@ public class ConcurrentHashSet<E> extends AbstractSet<E> implements java.io.Seri
* @param initialCapacity 初始大小
*/
public ConcurrentHashSet(int initialCapacity) {
map = new ConcurrentHashMap<>(initialCapacity);
map = new SafeConcurrentHashMap<>(initialCapacity);
}
/**
@ -46,7 +47,7 @@ public class ConcurrentHashSet<E> extends AbstractSet<E> implements java.io.Seri
* @param loadFactor 加载因子此参数决定数据增长时触发的百分比
*/
public ConcurrentHashSet(int initialCapacity, float loadFactor) {
map = new ConcurrentHashMap<>(initialCapacity, loadFactor);
map = new SafeConcurrentHashMap<>(initialCapacity, loadFactor);
}
/**
@ -57,7 +58,7 @@ public class ConcurrentHashSet<E> extends AbstractSet<E> implements java.io.Seri
* @param concurrencyLevel 线程并发度
*/
public ConcurrentHashSet(int initialCapacity, float loadFactor, int concurrencyLevel) {
map = new ConcurrentHashMap<>(initialCapacity, loadFactor, concurrencyLevel);
map = new SafeConcurrentHashMap<>(initialCapacity, loadFactor, concurrencyLevel);
}
/**
@ -67,10 +68,10 @@ public class ConcurrentHashSet<E> extends AbstractSet<E> implements java.io.Seri
public ConcurrentHashSet(Iterable<E> iter) {
if(iter instanceof Collection) {
final Collection<E> collection = (Collection<E>)iter;
map = new ConcurrentHashMap<>((int)(collection.size() / 0.75f));
map = new SafeConcurrentHashMap<>((int)(collection.size() / 0.75f));
this.addAll(collection);
}else {
map = new ConcurrentHashMap<>();
map = new SafeConcurrentHashMap<>();
for (E e : iter) {
this.add(e);
}

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

@ -36,6 +36,7 @@ import cn.hutool.core.convert.impl.UUIDConverter;
import cn.hutool.core.date.DateTime;
import cn.hutool.core.lang.Opt;
import cn.hutool.core.lang.TypeReference;
import cn.hutool.core.map.SafeConcurrentHashMap;
import cn.hutool.core.util.ClassLoaderUtil;
import cn.hutool.core.util.ClassUtil;
import cn.hutool.core.util.ObjectUtil;
@ -74,7 +75,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.AtomicInteger;
import java.util.concurrent.atomic.AtomicIntegerArray;
@ -172,7 +172,7 @@ public class ConverterRegistry implements Serializable {
if (null == customConverterMap) {
synchronized (this) {
if (null == customConverterMap) {
customConverterMap = new ConcurrentHashMap<>();
customConverterMap = new SafeConcurrentHashMap<>();
}
}
}
@ -384,7 +384,7 @@ public class ConverterRegistry implements Serializable {
* @return 转换器
*/
private ConverterRegistry defaultConverter() {
defaultConverterMap = new ConcurrentHashMap<>();
defaultConverterMap = new SafeConcurrentHashMap<>();
// 原始类型转换器
defaultConverterMap.put(int.class, new PrimitiveConverter(int.class));

View File

@ -1,10 +1,10 @@
package cn.hutool.core.date;
import cn.hutool.core.map.SafeConcurrentHashMap;
import cn.hutool.core.util.ObjectUtil;
import java.io.Serializable;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
/**
* 分组计时器<br>
@ -26,7 +26,7 @@ public class GroupTimeInterval implements Serializable {
*/
public GroupTimeInterval(boolean isNano) {
this.isNano = isNano;
groupMap = new ConcurrentHashMap<>();
groupMap = new SafeConcurrentHashMap<>();
}
/**

View File

@ -1,5 +1,7 @@
package cn.hutool.core.date.format;
import cn.hutool.core.map.SafeConcurrentHashMap;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.text.DateFormatSymbols;
@ -18,7 +20,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;
@ -449,7 +450,7 @@ public class FastDateParser extends AbstractDateBasic implements DateParser {
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

@ -1,6 +1,7 @@
package cn.hutool.core.date.format;
import cn.hutool.core.date.DateException;
import cn.hutool.core.map.SafeConcurrentHashMap;
import java.io.IOException;
import java.io.ObjectInputStream;
@ -11,7 +12,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;
/**
@ -1049,7 +1049,7 @@ public class FastDatePrinter extends AbstractDateBasic 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

@ -4,14 +4,13 @@ import cn.hutool.core.collection.TransIter;
import cn.hutool.core.lang.func.Func0;
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 = keyLockMap.computeIfAbsent(key, k -> new ReentrantLock());
keyLock.lock();
try {
// 双重检查防止在竞争锁的过程中已经有其它线程写入

View File

@ -1,14 +1,13 @@
package cn.hutool.core.lang;
import cn.hutool.core.lang.func.Func0;
import cn.hutool.core.map.MapUtil;
import cn.hutool.core.map.SafeConcurrentHashMap;
import cn.hutool.core.util.ArrayUtil;
import cn.hutool.core.util.ClassUtil;
import cn.hutool.core.util.ReflectUtil;
import cn.hutool.core.util.StrUtil;
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(String key, Func0<T> supplier) {
return (T) MapUtil.computeIfAbsent(POOL, key, (k)-> supplier.callWithRuntimeException());
return (T) POOL.computeIfAbsent(key, (k)-> supplier.callWithRuntimeException());
}
/**

View File

@ -1464,14 +1464,14 @@ public class MapUtil {
}
/**
* 方法来自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(Map<K, V> map, K key, Function<K, V> mappingFunction) {
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));

View File

@ -134,7 +134,7 @@ public class ReferenceConcurrentMap<K, V> implements ConcurrentMap<K, V>, Iterab
@Override
public V computeIfAbsent(K key, 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;
/**
@ -21,7 +20,7 @@ public class WeakConcurrentMap<K, V> extends ReferenceConcurrentMap<K, V> {
* 构造
*/
public WeakConcurrentMap() {
this(new ConcurrentHashMap<>());
this(new SafeConcurrentHashMap<>());
}
/**

View File

@ -1,6 +1,7 @@
package cn.hutool.core.text;
import cn.hutool.core.map.SafeConcurrentHashMap;
import cn.hutool.core.util.StrUtil;
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

@ -5,7 +5,7 @@ import cn.hutool.core.exceptions.UtilException;
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.SafeConcurrentHashMap;
import cn.hutool.core.map.WeakConcurrentMap;
import cn.hutool.core.text.CharPool;
@ -16,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}工具类
@ -50,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<Pair<String, ClassLoader>, Class<?>> CLASS_CACHE = new WeakConcurrentMap<>();
static {
@ -200,7 +199,7 @@ public class ClassLoaderUtil {
if (clazz == null) {
final String finalName = name;
final ClassLoader finalClassLoader = classLoader;
clazz = MapUtil.computeIfAbsent(CLASS_CACHE, Pair.of(name, classLoader), (key)-> doLoadClass(finalName, finalClassLoader, isInitialized));
clazz = CLASS_CACHE.computeIfAbsent(Pair.of(name, classLoader), (key)-> doLoadClass(finalName, finalClassLoader, isInitialized));
}
return clazz;
}

View File

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

View File

@ -1,5 +1,6 @@
package cn.hutool.db.dialect;
import cn.hutool.core.map.SafeConcurrentHashMap;
import cn.hutool.core.util.ClassLoaderUtil;
import cn.hutool.core.util.ReUtil;
import cn.hutool.core.util.StrUtil;
@ -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.util.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<>();
}
/**
@ -143,7 +143,6 @@ public abstract class AbstractDSFactory extends DSFactory {
DataSourceWrapper ds = dsMap.get(group);
if (ds != null) {
ds.close();
//noinspection resource
dsMap.remove(group);
}
}

View File

@ -1,7 +1,8 @@
package cn.hutool.db.meta;
import cn.hutool.core.map.SafeConcurrentHashMap;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
/**
* JDBC中字段类型枚举
@ -56,14 +57,14 @@ public enum JdbcType {
/**
* 构造
*
*
* @param code {@link java.sql.Types} 中对应的值
*/
JdbcType(int code) {
this.typeCode = code;
}
private static final Map<Integer, JdbcType> CODE_MAP = new ConcurrentHashMap<>(100, 1);
private static final Map<Integer, JdbcType> CODE_MAP = new SafeConcurrentHashMap<>(100, 1);
static {
for (JdbcType type : JdbcType.values()) {
CODE_MAP.put(type.typeCode, type);
@ -72,12 +73,12 @@ public enum JdbcType {
/**
* 通过{@link java.sql.Types}中对应int值找到enum值
*
*
* @param code Jdbc type值
* @return {@link JdbcType}
* @return {@code JdbcType}
*/
public static JdbcType valueOf(int code) {
return CODE_MAP.get(code);
}
}

View File

@ -1,13 +1,13 @@
package cn.hutool.db.nosql.mongo;
import cn.hutool.core.map.MapUtil;
import cn.hutool.core.map.SafeConcurrentHashMap;
import cn.hutool.core.util.ArrayUtil;
import cn.hutool.core.util.RuntimeUtil;
import cn.hutool.setting.Setting;
import java.util.Collection;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
/**
* {@link MongoDS}工厂类用于创建
@ -24,7 +24,7 @@ public class MongoFactory {
/**
* 数据源池
*/
private static final Map<String, MongoDS> DS_MAP = new ConcurrentHashMap<>();
private static final Map<String, MongoDS> DS_MAP = new SafeConcurrentHashMap<>();
// JVM关闭前关闭MongoDB连接
static {
@ -42,14 +42,7 @@ public class MongoFactory {
*/
public static MongoDS getDS(String host, int port) {
final String key = host + ":" + port;
MongoDS ds = DS_MAP.get(key);
if (null == ds) {
// 没有在池中加入之
ds = new MongoDS(host, port);
DS_MAP.put(key, ds);
}
return ds;
return DS_MAP.computeIfAbsent(key, (k)->new MongoDS(host, port));
}
/**

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);
@ -66,7 +67,7 @@ public class GlobalSerializeMapping {
*/
synchronized private static void putInternal(Type type, JSONSerializer<? extends JSON, ?> serializer) {
if(null == serializerMap) {
serializerMap = new ConcurrentHashMap<>();
serializerMap = new SafeConcurrentHashMap<>();
}
serializerMap.put(type, serializer);
}

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(String name) {
this.name = name;
logCache = new ConcurrentHashMap<>();
logCache = new SafeConcurrentHashMap<>();
}
/**

View File

@ -8,6 +8,7 @@ import cn.hutool.core.io.IORuntimeException;
import cn.hutool.core.io.IoUtil;
import cn.hutool.core.lang.Assert;
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;
/**
@ -938,7 +938,7 @@ public class ExcelWriter extends ExcelBase<ExcelWriter> {
*/
public ExcelWriter writeHeadRow(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.util.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.util.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.util.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>
@ -19,7 +19,7 @@ import java.util.concurrent.ConcurrentHashMap;
* <li>develop = ${classpath}/develop/db.setting</li>
* <li>production = ${classpath}/production/db.setting</li>
* </ol>
*
*
* @author Looly
*
*/
@ -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
/**
@ -48,7 +48,7 @@ public class Profile implements Serializable {
/**
* 构造编码UTF-8不使用变量
*
*
* @param profile 环境
*/
public Profile(String profile) {
@ -57,7 +57,7 @@ public class Profile implements Serializable {
/**
* 构造
*
*
* @param profile 环境
* @param charset 编码
* @param useVar 是否使用变量
@ -71,7 +71,7 @@ public class Profile implements Serializable {
/**
* 获取当前环境下的配置文件
*
*
* @param name 文件名如果没有扩展名默认为.setting
* @return 当前环境下配置文件
*/
@ -87,7 +87,7 @@ public class Profile implements Serializable {
/**
* 设置环境
*
*
* @param profile 环境
* @return 自身
*/
@ -98,7 +98,7 @@ public class Profile implements Serializable {
/**
* 设置编码
*
*
* @param charset 编码
* @return 自身
*/
@ -109,7 +109,7 @@ public class Profile implements Serializable {
/**
* 设置是否使用变量
*
*
* @param useVar 变量
* @return 自身
*/
@ -120,7 +120,7 @@ public class Profile implements Serializable {
/**
* 清空所有环境的配置文件
*
*
* @return 自身
*/
public Profile clear() {
@ -131,7 +131,7 @@ public class Profile implements Serializable {
// -------------------------------------------------------------------------------- Private method start
/**
* 修正文件名
*
*
* @param name 文件名
* @return 修正后的文件名
*/