mirror of
https://gitee.com/dromara/hutool.git
synced 2025-04-05 17:37:59 +08:00
增加SafeConcurrentHashMap
This commit is contained in:
parent
920fe44e50
commit
06fec1045c
@ -12,6 +12,7 @@
|
||||
* 【core 】 新增AnsiColors(改自Spring Boot)、AnsiColorWrapper,优化QrCodeUtil(pr#778@Gitee)
|
||||
* 【core 】 TemplateUtil的实现类增加getRawEngine方法(issues#2530@Github)
|
||||
* 【core 】 ImgUtil中颜色相关方法剥离到ColorUtil中
|
||||
* 【core 】 增加SafeConcurrentHashMap
|
||||
|
||||
### 🐞Bug修复
|
||||
* 【core 】 修复ObjectUtil.defaultIfXXX中NPE问题(pr#2603@Github)
|
||||
|
@ -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}表示无大小限制
|
||||
|
@ -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());
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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);
|
||||
|
@ -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));
|
||||
|
@ -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<>();
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -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];
|
||||
}
|
||||
|
@ -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>
|
||||
|
@ -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);
|
||||
|
||||
/**
|
||||
* 使用默认的pattern、timezone和locale获得缓存中的实例
|
||||
|
@ -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)));
|
||||
|
@ -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 {
|
||||
// 双重检查,防止在竞争锁的过程中已经有其它线程写入
|
||||
|
@ -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());
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -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));
|
||||
|
@ -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
|
||||
|
@ -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>
|
||||
* 方法来自Dubbo,见:issues#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);
|
||||
}
|
||||
}
|
@ -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<>());
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -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);
|
||||
|
||||
|
||||
/**
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
@ -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));
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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<>();
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -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;
|
||||
|
@ -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>
|
||||
|
@ -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>
|
||||
|
@ -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 修正后的文件名
|
||||
*/
|
||||
|
Loading…
Reference in New Issue
Block a user