This commit is contained in:
Looly 2024-03-26 19:38:13 +08:00
parent bdc964c882
commit b090fbdd3d
32 changed files with 295 additions and 360 deletions

View File

@ -15,8 +15,8 @@ package org.dromara.hutool.core.annotation;
import org.dromara.hutool.core.annotation.elements.HierarchicalAnnotatedElements; import org.dromara.hutool.core.annotation.elements.HierarchicalAnnotatedElements;
import org.dromara.hutool.core.annotation.elements.MetaAnnotatedElement; import org.dromara.hutool.core.annotation.elements.MetaAnnotatedElement;
import org.dromara.hutool.core.annotation.elements.RepeatableMetaAnnotatedElement; import org.dromara.hutool.core.annotation.elements.RepeatableMetaAnnotatedElement;
import org.dromara.hutool.core.map.reference.WeakKeyConcurrentMap;
import org.dromara.hutool.core.array.ArrayUtil; import org.dromara.hutool.core.array.ArrayUtil;
import org.dromara.hutool.core.map.reference.WeakConcurrentMap;
import org.dromara.hutool.core.util.ObjUtil; import org.dromara.hutool.core.util.ObjUtil;
import java.lang.annotation.Annotation; import java.lang.annotation.Annotation;
@ -133,7 +133,7 @@ import java.util.stream.Stream;
* <p><strong>缓存</strong> * <p><strong>缓存</strong>
* <p>为了避免注解以及{@link AnnotatedElement}层级结构解析过程中的大量反射调用 * <p>为了避免注解以及{@link AnnotatedElement}层级结构解析过程中的大量反射调用
* 工具类为{@link AnnotatedElement}及其元注解信息进行了缓存<br> * 工具类为{@link AnnotatedElement}及其元注解信息进行了缓存<br>
* 缓存功能默认基于{@link WeakKeyConcurrentMap}实现会在gc时自动回收部分缓存数据 * 缓存功能默认基于{@link WeakConcurrentMap}实现会在gc时自动回收部分缓存数据
* 但是若有必要也可以调用{@link #clearCaches()}方法主动清空缓存 * 但是若有必要也可以调用{@link #clearCaches()}方法主动清空缓存
* *
* @author huangchengxing * @author huangchengxing
@ -150,22 +150,22 @@ public class AnnotatedElementUtil {
/** /**
* 支持属性解析的{@link MetaAnnotatedElement}缓存 * 支持属性解析的{@link MetaAnnotatedElement}缓存
*/ */
private static final Map<AnnotatedElement, MetaAnnotatedElement<ResolvedAnnotationMapping>> RESOLVED_ELEMENT_CACHE = new WeakKeyConcurrentMap<>(); private static final Map<AnnotatedElement, MetaAnnotatedElement<ResolvedAnnotationMapping>> RESOLVED_ELEMENT_CACHE = new WeakConcurrentMap<>();
/** /**
* 不支持属性解析的{@link MetaAnnotatedElement}缓存 * 不支持属性解析的{@link MetaAnnotatedElement}缓存
*/ */
private static final Map<AnnotatedElement, MetaAnnotatedElement<GenericAnnotationMapping>> ELEMENT_CACHE = new WeakKeyConcurrentMap<>(); private static final Map<AnnotatedElement, MetaAnnotatedElement<GenericAnnotationMapping>> ELEMENT_CACHE = new WeakConcurrentMap<>();
/** /**
* 不支持属性解析的{@link RepeatableMetaAnnotatedElement}缓存 * 不支持属性解析的{@link RepeatableMetaAnnotatedElement}缓存
*/ */
private static final Map<AnnotatedElement, RepeatableMetaAnnotatedElement<ResolvedAnnotationMapping>> RESOLVED_REPEATABLE_ELEMENT_CACHE = new WeakKeyConcurrentMap<>(); private static final Map<AnnotatedElement, RepeatableMetaAnnotatedElement<ResolvedAnnotationMapping>> RESOLVED_REPEATABLE_ELEMENT_CACHE = new WeakConcurrentMap<>();
/** /**
* 不支持属性解析的{@link RepeatableMetaAnnotatedElement}缓存 * 不支持属性解析的{@link RepeatableMetaAnnotatedElement}缓存
*/ */
private static final Map<AnnotatedElement, RepeatableMetaAnnotatedElement<GenericAnnotationMapping>> REPEATABLE_ELEMENT_CACHE = new WeakKeyConcurrentMap<>(); private static final Map<AnnotatedElement, RepeatableMetaAnnotatedElement<GenericAnnotationMapping>> REPEATABLE_ELEMENT_CACHE = new WeakConcurrentMap<>();
// region ========== find ========== // region ========== find ==========

View File

@ -19,7 +19,7 @@ import org.dromara.hutool.core.exception.HutoolException;
import org.dromara.hutool.core.func.LambdaInfo; import org.dromara.hutool.core.func.LambdaInfo;
import org.dromara.hutool.core.func.LambdaUtil; import org.dromara.hutool.core.func.LambdaUtil;
import org.dromara.hutool.core.func.SerFunction; import org.dromara.hutool.core.func.SerFunction;
import org.dromara.hutool.core.map.reference.WeakKeyConcurrentMap; import org.dromara.hutool.core.map.reference.WeakConcurrentMap;
import org.dromara.hutool.core.reflect.FieldUtil; import org.dromara.hutool.core.reflect.FieldUtil;
import org.dromara.hutool.core.reflect.method.MethodUtil; import org.dromara.hutool.core.reflect.method.MethodUtil;
import org.dromara.hutool.core.text.CharSequenceUtil; import org.dromara.hutool.core.text.CharSequenceUtil;
@ -50,7 +50,7 @@ public class AnnotationUtil {
/** /**
* 直接声明的注解缓存 * 直接声明的注解缓存
*/ */
private static final Map<AnnotatedElement, Annotation[]> DECLARED_ANNOTATIONS_CACHE = new WeakKeyConcurrentMap<>(); private static final Map<AnnotatedElement, Annotation[]> DECLARED_ANNOTATIONS_CACHE = new WeakConcurrentMap<>();
/** /**
* 获取直接声明的注解若已有缓存则从缓存中获取 * 获取直接声明的注解若已有缓存则从缓存中获取

View File

@ -14,7 +14,7 @@ package org.dromara.hutool.core.annotation;
import org.dromara.hutool.core.array.ArrayUtil; import org.dromara.hutool.core.array.ArrayUtil;
import org.dromara.hutool.core.collection.CollUtil; import org.dromara.hutool.core.collection.CollUtil;
import org.dromara.hutool.core.map.reference.WeakKeyConcurrentMap; import org.dromara.hutool.core.map.reference.WeakConcurrentMap;
import org.dromara.hutool.core.reflect.method.MethodUtil; import org.dromara.hutool.core.reflect.method.MethodUtil;
import org.dromara.hutool.core.text.CharSequenceUtil; import org.dromara.hutool.core.text.CharSequenceUtil;
@ -337,7 +337,7 @@ public interface RepeatableAnnotationCollector {
/** /**
* 可重复注解对应的方法缓存 * 可重复注解对应的方法缓存
*/ */
private final Map<Class<? extends Annotation>, Object> repeatableMethodCache = new WeakKeyConcurrentMap<>(); private final Map<Class<? extends Annotation>, Object> repeatableMethodCache = new WeakConcurrentMap<>();
/** /**
* 构造 * 构造
@ -447,7 +447,7 @@ public interface RepeatableAnnotationCollector {
/** /**
* 可重复注解对应的方法缓存 * 可重复注解对应的方法缓存
*/ */
private final Map<Class<? extends Annotation>, Object> repeatableMethodCache = new WeakKeyConcurrentMap<>(); private final Map<Class<? extends Annotation>, Object> repeatableMethodCache = new WeakConcurrentMap<>();
/** /**
* 构造 * 构造

View File

@ -13,7 +13,7 @@
package org.dromara.hutool.core.bean; package org.dromara.hutool.core.bean;
import org.dromara.hutool.core.func.SerSupplier; import org.dromara.hutool.core.func.SerSupplier;
import org.dromara.hutool.core.map.reference.WeakKeyConcurrentMap; import org.dromara.hutool.core.map.reference.WeakConcurrentMap;
/** /**
* Bean属性缓存<br> * Bean属性缓存<br>
@ -27,7 +27,7 @@ public enum BeanDescCache {
*/ */
INSTANCE; INSTANCE;
private final WeakKeyConcurrentMap<Class<?>, BeanDesc> bdCache = new WeakKeyConcurrentMap<>(); private final WeakConcurrentMap<Class<?>, BeanDesc> bdCache = new WeakConcurrentMap<>();
/** /**
* 获得属性名和{@link BeanDesc}Map映射 * 获得属性名和{@link BeanDesc}Map映射

View File

@ -13,8 +13,8 @@
package org.dromara.hutool.core.bean; package org.dromara.hutool.core.bean;
import org.dromara.hutool.core.func.SerSupplier; import org.dromara.hutool.core.func.SerSupplier;
import org.dromara.hutool.core.map.reference.ReferenceKeyConcurrentMap; import org.dromara.hutool.core.map.reference.ReferenceConcurrentMap;
import org.dromara.hutool.core.map.reference.WeakKeyConcurrentMap; import org.dromara.hutool.core.map.reference.WeakConcurrentMap;
import java.beans.PropertyDescriptor; import java.beans.PropertyDescriptor;
import java.util.Map; import java.util.Map;
@ -31,8 +31,8 @@ public enum BeanInfoCache {
*/ */
INSTANCE; INSTANCE;
private final WeakKeyConcurrentMap<Class<?>, Map<String, PropertyDescriptor>> pdCache = new WeakKeyConcurrentMap<>(); private final WeakConcurrentMap<Class<?>, Map<String, PropertyDescriptor>> pdCache = new WeakConcurrentMap<>();
private final WeakKeyConcurrentMap<Class<?>, Map<String, PropertyDescriptor>> ignoreCasePdCache = new WeakKeyConcurrentMap<>(); private final WeakConcurrentMap<Class<?>, Map<String, PropertyDescriptor>> ignoreCasePdCache = new WeakConcurrentMap<>();
/** /**
* 获得属性名和{@link PropertyDescriptor}Map映射 * 获得属性名和{@link PropertyDescriptor}Map映射
@ -86,10 +86,10 @@ public enum BeanInfoCache {
* 根据是否忽略字段名的大小写返回不用Cache对象 * 根据是否忽略字段名的大小写返回不用Cache对象
* *
* @param ignoreCase 是否忽略大小写 * @param ignoreCase 是否忽略大小写
* @return {@link ReferenceKeyConcurrentMap} * @return {@link ReferenceConcurrentMap}
* @since 5.4.1 * @since 5.4.1
*/ */
private ReferenceKeyConcurrentMap<Class<?>, Map<String, PropertyDescriptor>> getCache(final boolean ignoreCase) { private ReferenceConcurrentMap<Class<?>, Map<String, PropertyDescriptor>> getCache(final boolean ignoreCase) {
return ignoreCase ? ignoreCasePdCache : pdCache; return ignoreCase ? ignoreCasePdCache : pdCache;
} }
} }

View File

@ -18,7 +18,7 @@ import org.dromara.hutool.core.lang.Assert;
import org.dromara.hutool.core.lang.mutable.Mutable; import org.dromara.hutool.core.lang.mutable.Mutable;
import org.dromara.hutool.core.lang.mutable.MutableObj; import org.dromara.hutool.core.lang.mutable.MutableObj;
import org.dromara.hutool.core.map.concurrent.SafeConcurrentHashMap; import org.dromara.hutool.core.map.concurrent.SafeConcurrentHashMap;
import org.dromara.hutool.core.map.reference.WeakKeyConcurrentMap; import org.dromara.hutool.core.map.reference.WeakConcurrentMap;
import java.io.Serializable; import java.io.Serializable;
import java.util.Iterator; import java.util.Iterator;
@ -33,7 +33,7 @@ import java.util.function.Predicate;
import java.util.stream.Collectors; import java.util.stream.Collectors;
/** /**
* 简单缓存无超时实现默认使用{@link WeakKeyConcurrentMap}实现缓存自动清理 * 简单缓存无超时实现默认使用{@link WeakConcurrentMap}实现缓存自动清理
* *
* @param <K> 键类型 * @param <K> 键类型
* @param <V> 值类型 * @param <V> 值类型
@ -57,7 +57,7 @@ public class SimpleCache<K, V> implements Iterable<Map.Entry<K, V>>, Serializabl
* 构造默认使用{@link WeakHashMap}实现缓存自动清理 * 构造默认使用{@link WeakHashMap}实现缓存自动清理
*/ */
public SimpleCache() { public SimpleCache() {
this(new WeakKeyConcurrentMap<>()); this(new WeakConcurrentMap<>());
} }
/** /**

View File

@ -15,9 +15,8 @@ package org.dromara.hutool.core.cache.impl;
import org.dromara.hutool.core.cache.CacheListener; import org.dromara.hutool.core.cache.CacheListener;
import org.dromara.hutool.core.lang.Opt; import org.dromara.hutool.core.lang.Opt;
import org.dromara.hutool.core.lang.mutable.Mutable; import org.dromara.hutool.core.lang.mutable.Mutable;
import org.dromara.hutool.core.map.reference.WeakKeyConcurrentMap; import org.dromara.hutool.core.lang.ref.Ref;
import org.dromara.hutool.core.map.reference.WeakConcurrentMap;
import java.lang.ref.Reference;
/** /**
* 弱引用缓存<br> * 弱引用缓存<br>
@ -39,16 +38,18 @@ public class WeakCache<K, V> extends TimedCache<K, V>{
* @param timeout 超时时常单位毫秒-1或0表示无限制 * @param timeout 超时时常单位毫秒-1或0表示无限制
*/ */
public WeakCache(final long timeout) { public WeakCache(final long timeout) {
super(timeout, new WeakKeyConcurrentMap<>()); super(timeout, new WeakConcurrentMap<>());
} }
@Override @Override
public WeakCache<K, V> setListener(final CacheListener<K, V> listener) { public WeakCache<K, V> setListener(final CacheListener<K, V> listener) {
super.setListener(listener); super.setListener(listener);
final WeakKeyConcurrentMap<Mutable<K>, CacheObj<K, V>> map = (WeakKeyConcurrentMap<Mutable<K>, CacheObj<K, V>>) this.cacheMap; final WeakConcurrentMap<Mutable<K>, CacheObj<K, V>> map = (WeakConcurrentMap<Mutable<K>, CacheObj<K, V>>) this.cacheMap;
// WeakKey回收之后key对应的值已经是null了因此此处的key也为null // WeakKey回收之后key对应的值已经是null了因此此处的key也为null
map.setPurgeListener((key, value)-> listener.onRemove(Opt.ofNullable(key).map(Reference::get).map(Mutable::get).get(), value.getValue())); map.setPurgeListener((key, value)-> listener.onRemove(
Opt.ofNullable(key).map(Ref::get).map(Mutable::get).get(),
Opt.ofNullable(value).map(Ref::get).map(CacheObj::getValue).get()));
return this; return this;
} }

View File

@ -16,10 +16,10 @@ import org.dromara.hutool.core.convert.AbstractConverter;
import org.dromara.hutool.core.convert.ConvertException; import org.dromara.hutool.core.convert.ConvertException;
import org.dromara.hutool.core.lang.EnumItem; import org.dromara.hutool.core.lang.EnumItem;
import org.dromara.hutool.core.map.MapUtil; import org.dromara.hutool.core.map.MapUtil;
import org.dromara.hutool.core.map.reference.WeakKeyConcurrentMap; import org.dromara.hutool.core.map.reference.WeakConcurrentMap;
import org.dromara.hutool.core.reflect.ClassUtil; import org.dromara.hutool.core.reflect.ClassUtil;
import org.dromara.hutool.core.reflect.method.MethodUtil;
import org.dromara.hutool.core.reflect.ModifierUtil; import org.dromara.hutool.core.reflect.ModifierUtil;
import org.dromara.hutool.core.reflect.method.MethodUtil;
import org.dromara.hutool.core.util.EnumUtil; import org.dromara.hutool.core.util.EnumUtil;
import java.lang.reflect.Method; import java.lang.reflect.Method;
@ -42,7 +42,7 @@ public class EnumConverter extends AbstractConverter {
*/ */
public static final EnumConverter INSTANCE = new EnumConverter(); public static final EnumConverter INSTANCE = new EnumConverter();
private static final WeakKeyConcurrentMap<Class<?>, Map<Class<?>, Method>> VALUE_OF_METHOD_CACHE = new WeakKeyConcurrentMap<>(); private static final WeakConcurrentMap<Class<?>, Map<Class<?>, Method>> VALUE_OF_METHOD_CACHE = new WeakConcurrentMap<>();
@Override @Override
protected Object convertInternal(final Class<?> targetClass, final Object value) { protected Object convertInternal(final Class<?> targetClass, final Object value) {

View File

@ -15,8 +15,9 @@ package org.dromara.hutool.core.func;
import org.dromara.hutool.core.exception.HutoolException; import org.dromara.hutool.core.exception.HutoolException;
import org.dromara.hutool.core.lang.Assert; import org.dromara.hutool.core.lang.Assert;
import org.dromara.hutool.core.lang.mutable.MutableEntry; import org.dromara.hutool.core.lang.mutable.MutableEntry;
import org.dromara.hutool.core.map.reference.WeakKeyConcurrentMap; import org.dromara.hutool.core.map.reference.WeakConcurrentMap;
import org.dromara.hutool.core.reflect.*; import org.dromara.hutool.core.reflect.ClassUtil;
import org.dromara.hutool.core.reflect.ReflectUtil;
import org.dromara.hutool.core.reflect.lookup.LookupUtil; import org.dromara.hutool.core.reflect.lookup.LookupUtil;
import org.dromara.hutool.core.reflect.method.MethodTypeUtil; import org.dromara.hutool.core.reflect.method.MethodTypeUtil;
import org.dromara.hutool.core.reflect.method.MethodUtil; import org.dromara.hutool.core.reflect.method.MethodUtil;
@ -37,7 +38,7 @@ public class LambdaFactory {
throw new IllegalAccessException(); throw new IllegalAccessException();
} }
private static final Map<MutableEntry<Class<?>, Executable>, Object> CACHE = new WeakKeyConcurrentMap<>(); private static final Map<MutableEntry<Class<?>, Executable>, Object> CACHE = new WeakConcurrentMap<>();
/** /**
* 构建Lambda * 构建Lambda

View File

@ -17,10 +17,10 @@ import org.dromara.hutool.core.classloader.ClassLoaderUtil;
import org.dromara.hutool.core.exception.HutoolException; import org.dromara.hutool.core.exception.HutoolException;
import org.dromara.hutool.core.lang.Assert; import org.dromara.hutool.core.lang.Assert;
import org.dromara.hutool.core.lang.Opt; import org.dromara.hutool.core.lang.Opt;
import org.dromara.hutool.core.map.reference.WeakKeyConcurrentMap; import org.dromara.hutool.core.map.reference.WeakConcurrentMap;
import org.dromara.hutool.core.reflect.ClassDescUtil; import org.dromara.hutool.core.reflect.ClassDescUtil;
import org.dromara.hutool.core.reflect.method.MethodUtil;
import org.dromara.hutool.core.reflect.ModifierUtil; import org.dromara.hutool.core.reflect.ModifierUtil;
import org.dromara.hutool.core.reflect.method.MethodUtil;
import java.io.Serializable; import java.io.Serializable;
import java.lang.invoke.SerializedLambda; import java.lang.invoke.SerializedLambda;
@ -37,7 +37,7 @@ import java.util.function.*;
*/ */
public class LambdaUtil { public class LambdaUtil {
private static final WeakKeyConcurrentMap<Object, LambdaInfo> CACHE = new WeakKeyConcurrentMap<>(); private static final WeakConcurrentMap<Object, LambdaInfo> CACHE = new WeakConcurrentMap<>();
/** /**
* 通过对象的方法或类的静态方法引用获取lambda实现类 * 通过对象的方法或类的静态方法引用获取lambda实现类

View File

@ -12,7 +12,7 @@
package org.dromara.hutool.core.lang.intern; package org.dromara.hutool.core.lang.intern;
import org.dromara.hutool.core.map.reference.WeakKeyConcurrentMap; import org.dromara.hutool.core.map.reference.WeakConcurrentMap;
import java.lang.ref.WeakReference; import java.lang.ref.WeakReference;
@ -25,7 +25,7 @@ import java.lang.ref.WeakReference;
*/ */
public class WeakIntern<T> implements Intern<T> { public class WeakIntern<T> implements Intern<T> {
private final WeakKeyConcurrentMap<T, WeakReference<T>> cache = new WeakKeyConcurrentMap<>(); private final WeakConcurrentMap<T, WeakReference<T>> cache = new WeakConcurrentMap<>();
@Override @Override
public T intern(final T sample) { public T intern(final T sample) {

View File

@ -0,0 +1,55 @@
/*
* Copyright (c) 2024. looly(loolly@aliyun.com)
* Hutool is licensed under Mulan PSL v2.
* You can use this software according to the terms and conditions of the Mulan PSL v2.
* You may obtain a copy of Mulan PSL v2 at:
* https://license.coscl.org.cn/MulanPSL2
* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
* See the Mulan PSL v2 for more details.
*/
package org.dromara.hutool.core.lang.ref;
import org.dromara.hutool.core.util.ObjUtil;
import java.lang.ref.PhantomReference;
import java.lang.ref.ReferenceQueue;
import java.util.Objects;
/**
* 虚引用对象在GC时发现虚引用对象会将{@link PhantomReference}插入{@link ReferenceQueue} <br>
* 此时对象未被真正回收要等到{@link ReferenceQueue}被真正处理后才会被回收
*
* @param <T> 键类型
*/
public class PhantomObj<T> extends PhantomReference<T> implements Ref<T>{
private final int hashCode;
/**
* 构造
*
* @param obj 原始对象
* @param queue {@link ReferenceQueue}
*/
public PhantomObj(final T obj, final ReferenceQueue<? super T> queue) {
super(obj, queue);
hashCode = Objects.hashCode(obj);
}
@Override
public int hashCode() {
return hashCode;
}
@Override
public boolean equals(final Object other) {
if (other == this) {
return true;
} else if (other instanceof PhantomObj) {
return ObjUtil.equals(((PhantomObj<?>) other).get(), get());
}
return false;
}
}

View File

@ -0,0 +1,30 @@
/*
* Copyright (c) 2024. looly(loolly@aliyun.com)
* Hutool is licensed under Mulan PSL v2.
* You can use this software according to the terms and conditions of the Mulan PSL v2.
* You may obtain a copy of Mulan PSL v2 at:
* https://license.coscl.org.cn/MulanPSL2
* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
* See the Mulan PSL v2 for more details.
*/
package org.dromara.hutool.core.lang.ref;
/**
* 针对{@link java.lang.ref.Reference}的接口定义用于扩展功能<br>
* 例如提供自定义的无需回收对象
*
* @param <T> 对象类型
*/
@FunctionalInterface
public interface Ref<T> {
/**
* 获取引用的原始对象
*
* @return 原始对象
*/
T get();
}

View File

@ -21,6 +21,10 @@ import java.lang.ref.ReferenceQueue;
* @author looly * @author looly
*/ */
public enum ReferenceType { public enum ReferenceType {
/**
* 强引用不回收
*/
STRONG,
/** /**
* 软引用在GC报告内存不足时会被GC回收 * 软引用在GC报告内存不足时会被GC回收
*/ */

View File

@ -79,4 +79,16 @@ public class ReferenceUtil {
public static <T> T get(final Reference<T> obj) { public static <T> T get(final Reference<T> obj) {
return ObjUtil.apply(obj, Reference::get); return ObjUtil.apply(obj, Reference::get);
} }
/**
* {@code null}全的解包获取原始对象
*
* @param <T> 对象类型
* @param obj Ref对象
* @return 原始对象 or {@code null}
* @since 6.0.0
*/
public static <T> T get(final Ref<T> obj) {
return ObjUtil.apply(obj, Ref::get);
}
} }

View File

@ -23,7 +23,7 @@ import java.util.Objects;
* *
* @param <T> 键类型 * @param <T> 键类型
*/ */
public class SoftObj<T> extends SoftReference<T> { public class SoftObj<T> extends SoftReference<T> implements Ref<T>{
private final int hashCode; private final int hashCode;
/** /**

View File

@ -0,0 +1,56 @@
/*
* Copyright (c) 2024. looly(loolly@aliyun.com)
* Hutool is licensed under Mulan PSL v2.
* You can use this software according to the terms and conditions of the Mulan PSL v2.
* You may obtain a copy of Mulan PSL v2 at:
* https://license.coscl.org.cn/MulanPSL2
* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
* See the Mulan PSL v2 for more details.
*/
package org.dromara.hutool.core.lang.ref;
import org.dromara.hutool.core.util.ObjUtil;
import java.util.Objects;
/**
* 弱引用对象在GC时发现弱引用会回收其对象
*
* @param <T> 键类型
*/
public class StrongObj<T> implements Ref<T> {
private final T obj;
/**
* 构造
*
* @param obj 原始对象
*/
public StrongObj(final T obj) {
this.obj = obj;
}
@Override
public T get() {
return this.obj;
}
@Override
public int hashCode() {
return Objects.hashCode(obj);
}
@Override
public boolean equals(final Object other) {
if (other == this) {
return true;
} else if (other instanceof StrongObj) {
return ObjUtil.equals(((StrongObj<?>) other).get(), get());
}
return false;
}
}

View File

@ -23,7 +23,7 @@ import java.util.Objects;
* *
* @param <T> 键类型 * @param <T> 键类型
*/ */
public class WeakObj<T> extends WeakReference<T> { public class WeakObj<T> extends WeakReference<T> implements Ref<T>{
private final int hashCode; private final int hashCode;
/** /**

View File

@ -12,8 +12,9 @@
package org.dromara.hutool.core.map.reference; package org.dromara.hutool.core.map.reference;
import org.dromara.hutool.core.map.MapUtil; import org.dromara.hutool.core.lang.ref.Ref;
import org.dromara.hutool.core.lang.ref.ReferenceUtil; import org.dromara.hutool.core.lang.ref.ReferenceUtil;
import org.dromara.hutool.core.map.MapUtil;
import java.io.Serializable; import java.io.Serializable;
import java.lang.ref.Reference; import java.lang.ref.Reference;
@ -34,13 +35,13 @@ import java.util.function.Function;
public abstract class ReferenceConcurrentMap<K, V> implements ConcurrentMap<K, V>, Iterable<Map.Entry<K, V>>, Serializable { public abstract class ReferenceConcurrentMap<K, V> implements ConcurrentMap<K, V>, Iterable<Map.Entry<K, V>>, Serializable {
private static final long serialVersionUID = 1L; private static final long serialVersionUID = 1L;
final ConcurrentMap<Reference<K>, Reference<V>> raw; final ConcurrentMap<Ref<K>, Ref<V>> raw;
private final ReferenceQueue<K> lastKeyQueue; private final ReferenceQueue<K> lastKeyQueue;
private final ReferenceQueue<V> lastValueQueue; private final ReferenceQueue<V> lastValueQueue;
/** /**
* 回收监听 * 回收监听
*/ */
private BiConsumer<Reference<? extends K>, Reference<? extends V>> purgeListener; private BiConsumer<Ref<? extends K>, Ref<? extends V>> purgeListener;
// region 构造 // region 构造
@ -49,7 +50,7 @@ public abstract class ReferenceConcurrentMap<K, V> implements ConcurrentMap<K, V
* *
* @param raw {@link ConcurrentMap}实现 * @param raw {@link ConcurrentMap}实现
*/ */
public ReferenceConcurrentMap(final ConcurrentMap<Reference<K>, Reference<V>> raw) { public ReferenceConcurrentMap(final ConcurrentMap<Ref<K>, Ref<V>> raw) {
this.raw = raw; this.raw = raw;
lastKeyQueue = new ReferenceQueue<>(); lastKeyQueue = new ReferenceQueue<>();
lastValueQueue = new ReferenceQueue<>(); lastValueQueue = new ReferenceQueue<>();
@ -61,7 +62,7 @@ public abstract class ReferenceConcurrentMap<K, V> implements ConcurrentMap<K, V
* *
* @param purgeListener 监听函数 * @param purgeListener 监听函数
*/ */
public void setPurgeListener(final BiConsumer<Reference<? extends K>, Reference<? extends V>> purgeListener) { public void setPurgeListener(final BiConsumer<Ref<? extends K>, Ref<? extends V>> purgeListener) {
this.purgeListener = purgeListener; this.purgeListener = purgeListener;
} }
@ -98,14 +99,14 @@ public abstract class ReferenceConcurrentMap<K, V> implements ConcurrentMap<K, V
@Override @Override
public V put(final K key, final V value) { public V put(final K key, final V value) {
this.purgeStale(); this.purgeStale();
final Reference<V> vReference = this.raw.put(wrapKey(key), wrapValue(value)); final Ref<V> vReference = this.raw.put(wrapKey(key), wrapValue(value));
return unwrap(vReference); return unwrap(vReference);
} }
@Override @Override
public V putIfAbsent(final K key, final V value) { public V putIfAbsent(final K key, final V value) {
this.purgeStale(); this.purgeStale();
final Reference<V> vReference = this.raw.putIfAbsent(wrapKey(key), wrapValue(value)); final Ref<V> vReference = this.raw.putIfAbsent(wrapKey(key), wrapValue(value));
return unwrap(vReference); return unwrap(vReference);
} }
@ -117,7 +118,7 @@ public abstract class ReferenceConcurrentMap<K, V> implements ConcurrentMap<K, V
@Override @Override
public V replace(final K key, final V value) { public V replace(final K key, final V value) {
this.purgeStale(); this.purgeStale();
final Reference<V> vReference = this.raw.replace(wrapKey(key), wrapValue(value)); final Ref<V> vReference = this.raw.replace(wrapKey(key), wrapValue(value));
return unwrap(vReference); return unwrap(vReference);
} }
@ -136,7 +137,7 @@ public abstract class ReferenceConcurrentMap<K, V> implements ConcurrentMap<K, V
@Override @Override
public V computeIfAbsent(final K key, final Function<? super K, ? extends V> mappingFunction) { public V computeIfAbsent(final K key, final Function<? super K, ? extends V> mappingFunction) {
this.purgeStale(); this.purgeStale();
final Reference<V> vReference = this.raw.computeIfAbsent(wrapKey(key), final Ref<V> vReference = this.raw.computeIfAbsent(wrapKey(key),
kReference -> wrapValue(mappingFunction.apply(unwrap(kReference)))); kReference -> wrapValue(mappingFunction.apply(unwrap(kReference))));
return unwrap(vReference); return unwrap(vReference);
} }
@ -144,7 +145,7 @@ public abstract class ReferenceConcurrentMap<K, V> implements ConcurrentMap<K, V
@Override @Override
public V computeIfPresent(final K key, final BiFunction<? super K, ? super V, ? extends V> remappingFunction) { public V computeIfPresent(final K key, final BiFunction<? super K, ? super V, ? extends V> remappingFunction) {
this.purgeStale(); this.purgeStale();
final Reference<V> vReference = this.raw.computeIfPresent(wrapKey(key), final Ref<V> vReference = this.raw.computeIfPresent(wrapKey(key),
(kReference, vReference1) -> wrapValue(remappingFunction.apply(unwrap(kReference), unwrap(vReference1)))); (kReference, vReference1) -> wrapValue(remappingFunction.apply(unwrap(kReference), unwrap(vReference1))));
return unwrap(vReference); return unwrap(vReference);
} }
@ -173,11 +174,11 @@ public abstract class ReferenceConcurrentMap<K, V> implements ConcurrentMap<K, V
@Override @Override
public Set<K> keySet() { public Set<K> keySet() {
this.purgeStale(); this.purgeStale();
final Set<Reference<K>> referenceSet = this.raw.keySet(); final Set<Ref<K>> referenceSet = this.raw.keySet();
return new AbstractSet<K>() { return new AbstractSet<K>() {
@Override @Override
public Iterator<K> iterator() { public Iterator<K> iterator() {
final Iterator<Reference<K>> referenceIter = referenceSet.iterator(); final Iterator<Ref<K>> referenceIter = referenceSet.iterator();
return new Iterator<K>() { return new Iterator<K>() {
@Override @Override
public boolean hasNext() { public boolean hasNext() {
@ -201,11 +202,11 @@ public abstract class ReferenceConcurrentMap<K, V> implements ConcurrentMap<K, V
@Override @Override
public Collection<V> values() { public Collection<V> values() {
this.purgeStale(); this.purgeStale();
final Collection<Reference<V>> referenceValues = this.raw.values(); final Collection<Ref<V>> referenceValues = this.raw.values();
return new AbstractCollection<V>() { return new AbstractCollection<V>() {
@Override @Override
public Iterator<V> iterator() { public Iterator<V> iterator() {
final Iterator<Reference<V>> referenceIter = referenceValues.iterator(); final Iterator<Ref<V>> referenceIter = referenceValues.iterator();
return new Iterator<V>() { return new Iterator<V>() {
@Override @Override
public boolean hasNext() { public boolean hasNext() {
@ -229,11 +230,11 @@ public abstract class ReferenceConcurrentMap<K, V> implements ConcurrentMap<K, V
@Override @Override
public Set<Entry<K, V>> entrySet() { public Set<Entry<K, V>> entrySet() {
this.purgeStale(); this.purgeStale();
final Set<Entry<Reference<K>, Reference<V>>> referenceEntrySet = this.raw.entrySet(); final Set<Entry<Ref<K>, Ref<V>>> referenceEntrySet = this.raw.entrySet();
return new AbstractSet<Entry<K, V>>() { return new AbstractSet<Entry<K, V>>() {
@Override @Override
public Iterator<Entry<K, V>> iterator() { public Iterator<Entry<K, V>> iterator() {
final Iterator<Entry<Reference<K>, Reference<V>>> referenceIter = referenceEntrySet.iterator(); final Iterator<Entry<Ref<K>, Ref<V>>> referenceIter = referenceEntrySet.iterator();
return new Iterator<Entry<K, V>>() { return new Iterator<Entry<K, V>>() {
@Override @Override
public boolean hasNext() { public boolean hasNext() {
@ -242,7 +243,7 @@ public abstract class ReferenceConcurrentMap<K, V> implements ConcurrentMap<K, V
@Override @Override
public Entry<K, V> next() { public Entry<K, V> next() {
final Entry<Reference<K>, Reference<V>> next = referenceIter.next(); final Entry<Ref<K>, Ref<V>> next = referenceIter.next();
return new Entry<K, V>() { return new Entry<K, V>() {
@Override @Override
public K getKey() { public K getKey() {
@ -300,11 +301,11 @@ public abstract class ReferenceConcurrentMap<K, V> implements ConcurrentMap<K, V
*/ */
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
private void purgeStale() { private void purgeStale() {
Reference<? extends K> key; Ref<? extends K> key;
Reference<? extends V> value; Ref<? extends V> value;
// 清除无效key对应键值对 // 清除无效key对应键值对
while ((key = this.lastKeyQueue.poll()) != null) { while ((key = (Ref<? extends K>) this.lastKeyQueue.poll()) != null) {
value = this.raw.remove(key); value = this.raw.remove(key);
if (null != purgeListener) { if (null != purgeListener) {
purgeListener.accept(key, value); purgeListener.accept(key, value);
@ -312,8 +313,8 @@ public abstract class ReferenceConcurrentMap<K, V> implements ConcurrentMap<K, V
} }
// 清除无效value对应的键值对 // 清除无效value对应的键值对
while ((value = this.lastValueQueue.poll()) != null) { while ((value = (Ref<? extends V>) this.lastValueQueue.poll()) != null) {
MapUtil.removeByValue(this.raw, (Reference<V>) value); MapUtil.removeByValue(this.raw, (Ref<V>) value);
if (null != purgeListener) { if (null != purgeListener) {
purgeListener.accept(null, value); purgeListener.accept(null, value);
} }
@ -327,7 +328,7 @@ public abstract class ReferenceConcurrentMap<K, V> implements ConcurrentMap<K, V
* @param queue {@link ReferenceQueue} * @param queue {@link ReferenceQueue}
* @return {@link Reference} * @return {@link Reference}
*/ */
abstract Reference<K> wrapKey(final K key, final ReferenceQueue<? super K> queue); abstract Ref<K> wrapKey(final K key, final ReferenceQueue<? super K> queue);
/** /**
* 根据Reference类型构建value对应的{@link Reference} * 根据Reference类型构建value对应的{@link Reference}
@ -336,7 +337,7 @@ public abstract class ReferenceConcurrentMap<K, V> implements ConcurrentMap<K, V
* @param queue {@link ReferenceQueue} * @param queue {@link ReferenceQueue}
* @return {@link Reference} * @return {@link Reference}
*/ */
abstract Reference<V> wrapValue(final V value, final ReferenceQueue<? super V> queue); abstract Ref<V> wrapValue(final V value, final ReferenceQueue<? super V> queue);
/** /**
* 根据Reference类型构建key对应的{@link Reference} * 根据Reference类型构建key对应的{@link Reference}
@ -345,7 +346,7 @@ public abstract class ReferenceConcurrentMap<K, V> implements ConcurrentMap<K, V
* @return {@link Reference} * @return {@link Reference}
*/ */
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
private Reference<K> wrapKey(final Object key) { private Ref<K> wrapKey(final Object key) {
return wrapKey((K) key, this.lastKeyQueue); return wrapKey((K) key, this.lastKeyQueue);
} }
@ -356,7 +357,7 @@ public abstract class ReferenceConcurrentMap<K, V> implements ConcurrentMap<K, V
* @return {@link Reference} * @return {@link Reference}
*/ */
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
private Reference<V> wrapValue(final Object value) { private Ref<V> wrapValue(final Object value) {
return wrapValue((V) value, this.lastValueQueue); return wrapValue((V) value, this.lastValueQueue);
} }
@ -367,7 +368,7 @@ public abstract class ReferenceConcurrentMap<K, V> implements ConcurrentMap<K, V
* @param obj 对象 * @param obj 对象
* @return * @return
*/ */
private static <T> T unwrap(final Reference<T> obj) { private static <T> T unwrap(final Ref<T> obj) {
return ReferenceUtil.get(obj); return ReferenceUtil.get(obj);
} }
} }

View File

@ -1,247 +0,0 @@
/*
* Copyright (c) 2023-2024. looly(loolly@aliyun.com)
* Hutool is licensed under Mulan PSL v2.
* You can use this software according to the terms and conditions of the Mulan PSL v2.
* You may obtain a copy of Mulan PSL v2 at:
* https://license.coscl.org.cn/MulanPSL2
* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
* See the Mulan PSL v2 for more details.
*/
package org.dromara.hutool.core.map.reference;
import org.dromara.hutool.core.collection.CollUtil;
import org.dromara.hutool.core.lang.ref.ReferenceType;
import org.dromara.hutool.core.lang.ref.SoftObj;
import org.dromara.hutool.core.lang.ref.WeakObj;
import java.io.Serializable;
import java.lang.ref.Reference;
import java.lang.ref.ReferenceQueue;
import java.util.*;
import java.util.concurrent.ConcurrentMap;
import java.util.function.BiConsumer;
import java.util.function.BiFunction;
import java.util.function.Function;
import java.util.stream.Collectors;
/**
* 线程安全的ReferenceMap实现<br>
* 参考jdk.management.resource.internal.WeakKeyConcurrentHashMap
*
* @param <K> 键类型
* @param <V> 值类型
* @author looly
*/
public class ReferenceKeyConcurrentMap<K, V> implements ConcurrentMap<K, V>, Iterable<Map.Entry<K, V>>, Serializable {
private static final long serialVersionUID = 1L;
final ConcurrentMap<Reference<K>, V> raw;
private final ReferenceQueue<K> lastQueue;
private final ReferenceType keyType;
/**
* 回收监听
*/
private BiConsumer<Reference<? extends K>, V> purgeListener;
// region 构造
/**
* 构造
*
* @param raw {@link ConcurrentMap}实现
* @param referenceType Reference类型
*/
public ReferenceKeyConcurrentMap(final ConcurrentMap<Reference<K>, V> raw, final ReferenceType referenceType) {
this.raw = raw;
this.keyType = referenceType;
lastQueue = new ReferenceQueue<>();
}
// endregion
/**
* 设置对象回收清除监听
*
* @param purgeListener 监听函数
*/
public void setPurgeListener(final BiConsumer<Reference<? extends K>, V> purgeListener) {
this.purgeListener = purgeListener;
}
@Override
public int size() {
this.purgeStaleKeys();
return this.raw.size();
}
@Override
public boolean isEmpty() {
return 0 == size();
}
@SuppressWarnings("unchecked")
@Override
public V get(final Object key) {
this.purgeStaleKeys();
return this.raw.get(ofKey((K) key, null));
}
@SuppressWarnings("unchecked")
@Override
public boolean containsKey(final Object key) {
this.purgeStaleKeys();
return this.raw.containsKey(ofKey((K) key, null));
}
@Override
public boolean containsValue(final Object value) {
this.purgeStaleKeys();
return this.raw.containsValue(value);
}
@Override
public V put(final K key, final V value) {
this.purgeStaleKeys();
return this.raw.put(ofKey(key, this.lastQueue), value);
}
@Override
public V putIfAbsent(final K key, final V value) {
this.purgeStaleKeys();
return this.raw.putIfAbsent(ofKey(key, this.lastQueue), value);
}
@Override
public void putAll(final Map<? extends K, ? extends V> m) {
m.forEach(this::put);
}
@Override
public V replace(final K key, final V value) {
this.purgeStaleKeys();
return this.raw.replace(ofKey(key, this.lastQueue), value);
}
@Override
public boolean replace(final K key, final V oldValue, final V newValue) {
this.purgeStaleKeys();
return this.raw.replace(ofKey(key, this.lastQueue), oldValue, newValue);
}
@Override
public void replaceAll(final BiFunction<? super K, ? super V, ? extends V> function) {
this.purgeStaleKeys();
this.raw.replaceAll((kWeakKey, value) -> function.apply(kWeakKey.get(), value));
}
@Override
public V computeIfAbsent(final K key, final Function<? super K, ? extends V> mappingFunction) {
this.purgeStaleKeys();
return this.raw.computeIfAbsent(ofKey(key, this.lastQueue), kWeakKey -> mappingFunction.apply(key));
}
@Override
public V computeIfPresent(final K key, final BiFunction<? super K, ? super V, ? extends V> remappingFunction) {
this.purgeStaleKeys();
return this.raw.computeIfPresent(ofKey(key, this.lastQueue), (kWeakKey, value) -> remappingFunction.apply(key, value));
}
@SuppressWarnings("unchecked")
@Override
public V remove(final Object key) {
this.purgeStaleKeys();
return this.raw.remove(ofKey((K) key, null));
}
@SuppressWarnings("unchecked")
@Override
public boolean remove(final Object key, final Object value) {
this.purgeStaleKeys();
return this.raw.remove(ofKey((K) key, null), value);
}
@SuppressWarnings("StatementWithEmptyBody")
@Override
public void clear() {
this.raw.clear();
while (lastQueue.poll() != null) ;
}
@Override
public Set<K> keySet() {
this.purgeStaleKeys();
// TODO 非高效方式的set转换应该返回一个view
final Collection<K> trans = CollUtil.trans(this.raw.keySet(), (reference) -> null == reference ? null : reference.get());
return new HashSet<>(trans);
}
@Override
public Collection<V> values() {
this.purgeStaleKeys();
return this.raw.values();
}
@Override
public Set<Entry<K, V>> entrySet() {
this.purgeStaleKeys();
return this.raw.entrySet().stream()
.map(entry -> new AbstractMap.SimpleImmutableEntry<>(entry.getKey().get(), entry.getValue()))
.collect(Collectors.toSet());
}
@Override
public void forEach(final BiConsumer<? super K, ? super V> action) {
this.purgeStaleKeys();
this.raw.forEach((key, value)-> action.accept(key.get(), value));
}
@Override
public Iterator<Entry<K, V>> iterator() {
return entrySet().iterator();
}
@Override
public V compute(final K key, final BiFunction<? super K, ? super V, ? extends V> remappingFunction) {
this.purgeStaleKeys();
return this.raw.compute(ofKey(key, this.lastQueue), (kWeakKey, value) -> remappingFunction.apply(key, value));
}
@Override
public V merge(final K key, final V value, final BiFunction<? super V, ? super V, ? extends V> remappingFunction) {
this.purgeStaleKeys();
return this.raw.merge(ofKey(key, this.lastQueue), value, remappingFunction);
}
/**
* 清除被回收的键
*/
private void purgeStaleKeys() {
Reference<? extends K> reference;
V value;
while ((reference = this.lastQueue.poll()) != null) {
value = this.raw.remove(reference);
if (null != purgeListener) {
purgeListener.accept(reference, value);
}
}
}
/**
* 根据Reference类型构建key对应的{@link Reference}
*
* @param key
* @param queue {@link ReferenceQueue}
* @return {@link Reference}
*/
private Reference<K> ofKey(final K key, final ReferenceQueue<? super K> queue) {
switch (keyType) {
case WEAK:
return new WeakObj<>(key, queue);
case SOFT:
return new SoftObj<>(key, queue);
}
throw new IllegalArgumentException("Unsupported key type: " + keyType);
}
}

View File

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2023-2024. looly(loolly@aliyun.com) * Copyright (c) 2024. looly(loolly@aliyun.com)
* Hutool is licensed under Mulan PSL v2. * Hutool is licensed under Mulan PSL v2.
* You can use this software according to the terms and conditions of the Mulan PSL v2. * You can use this software according to the terms and conditions of the Mulan PSL v2.
* You may obtain a copy of Mulan PSL v2 at: * You may obtain a copy of Mulan PSL v2 at:
@ -12,27 +12,29 @@
package org.dromara.hutool.core.map.reference; package org.dromara.hutool.core.map.reference;
import org.dromara.hutool.core.lang.ref.ReferenceType; import org.dromara.hutool.core.lang.ref.Ref;
import org.dromara.hutool.core.lang.ref.SoftObj;
import org.dromara.hutool.core.map.concurrent.SafeConcurrentHashMap; import org.dromara.hutool.core.map.concurrent.SafeConcurrentHashMap;
import java.lang.ref.Reference; import java.lang.ref.ReferenceQueue;
import java.util.concurrent.ConcurrentMap; import java.util.concurrent.ConcurrentMap;
/** /**
* 线程安全的SoftMap实现<br> * 线程安全的SoftMap实现<br>
* 键和值都为Soft引用在GC报告内存不足时会被GC回收
* *
* @param <K> 键类型 * @param <K> 键类型
* @param <V> 值类型 * @param <V> 值类型
* @author looly * @author looly
* @since 6.0.0 * @since 6.0.0
*/ */
public class SoftKeyConcurrentMap<K, V> extends ReferenceKeyConcurrentMap<K, V> { public class SoftConcurrentMap<K, V> extends ReferenceConcurrentMap<K, V> {
private static final long serialVersionUID = 1L; private static final long serialVersionUID = 1L;
/** /**
* 构造 * 构造
*/ */
public SoftKeyConcurrentMap() { public SoftConcurrentMap() {
this(new SafeConcurrentHashMap<>()); this(new SafeConcurrentHashMap<>());
} }
@ -41,7 +43,17 @@ public class SoftKeyConcurrentMap<K, V> extends ReferenceKeyConcurrentMap<K, V>
* *
* @param raw {@link ConcurrentMap}实现 * @param raw {@link ConcurrentMap}实现
*/ */
public SoftKeyConcurrentMap(final ConcurrentMap<Reference<K>, V> raw) { public SoftConcurrentMap(final ConcurrentMap<Ref<K>, Ref<V>> raw) {
super(raw, ReferenceType.SOFT); super(raw);
}
@Override
Ref<K> wrapKey(final K key, final ReferenceQueue<? super K> queue) {
return new SoftObj<>(key, queue);
}
@Override
Ref<V> wrapValue(final V value, final ReferenceQueue<? super V> queue) {
return new SoftObj<>(value, queue);
} }
} }

View File

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2023-2024. looly(loolly@aliyun.com) * Copyright (c) 2024. looly(loolly@aliyun.com)
* Hutool is licensed under Mulan PSL v2. * Hutool is licensed under Mulan PSL v2.
* You can use this software according to the terms and conditions of the Mulan PSL v2. * You can use this software according to the terms and conditions of the Mulan PSL v2.
* You may obtain a copy of Mulan PSL v2 at: * You may obtain a copy of Mulan PSL v2 at:
@ -12,28 +12,29 @@
package org.dromara.hutool.core.map.reference; package org.dromara.hutool.core.map.reference;
import org.dromara.hutool.core.lang.ref.ReferenceType; import org.dromara.hutool.core.lang.ref.Ref;
import org.dromara.hutool.core.lang.ref.WeakObj;
import org.dromara.hutool.core.map.concurrent.SafeConcurrentHashMap; import org.dromara.hutool.core.map.concurrent.SafeConcurrentHashMap;
import java.lang.ref.Reference; import java.lang.ref.ReferenceQueue;
import java.util.concurrent.ConcurrentMap; import java.util.concurrent.ConcurrentMap;
/** /**
* 线程安全的WeakMap实现<br> * 线程安全的WeakMap实现<br>
* 参考jdk.management.resource.internal.WeakKeyConcurrentHashMap * 键和值都为Weak引用在GC时发现弱引用会回收其对象
* *
* @param <K> 键类型 * @param <K> 键类型
* @param <V> 值类型 * @param <V> 值类型
* @author looly * @author looly
* @since 5.8.0 * @since 6.0.0
*/ */
public class WeakKeyConcurrentMap<K, V> extends ReferenceKeyConcurrentMap<K, V> { public class WeakConcurrentMap<K, V> extends ReferenceConcurrentMap<K, V> {
private static final long serialVersionUID = 1L; private static final long serialVersionUID = 1L;
/** /**
* 构造 * 构造
*/ */
public WeakKeyConcurrentMap() { public WeakConcurrentMap() {
this(new SafeConcurrentHashMap<>()); this(new SafeConcurrentHashMap<>());
} }
@ -42,7 +43,17 @@ public class WeakKeyConcurrentMap<K, V> extends ReferenceKeyConcurrentMap<K, V>
* *
* @param raw {@link ConcurrentMap}实现 * @param raw {@link ConcurrentMap}实现
*/ */
public WeakKeyConcurrentMap(final ConcurrentMap<Reference<K>, V> raw) { public WeakConcurrentMap(final ConcurrentMap<Ref<K>, Ref<V>> raw) {
super(raw, ReferenceType.WEAK); super(raw);
}
@Override
Ref<K> wrapKey(final K key, final ReferenceQueue<? super K> queue) {
return new WeakObj<>(key, queue);
}
@Override
Ref<V> wrapValue(final V value, final ReferenceQueue<? super V> queue) {
return new WeakObj<>(value, queue);
} }
} }

View File

@ -13,7 +13,7 @@
package org.dromara.hutool.core.reflect; package org.dromara.hutool.core.reflect;
import org.dromara.hutool.core.convert.Convert; import org.dromara.hutool.core.convert.Convert;
import org.dromara.hutool.core.map.reference.WeakKeyConcurrentMap; import org.dromara.hutool.core.map.reference.WeakConcurrentMap;
import java.lang.reflect.ParameterizedType; import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type; import java.lang.reflect.Type;
@ -29,7 +29,7 @@ import java.util.Map;
*/ */
public class ActualTypeMapperPool { public class ActualTypeMapperPool {
private static final WeakKeyConcurrentMap<Type, Map<Type, Type>> CACHE = new WeakKeyConcurrentMap<>(); private static final WeakConcurrentMap<Type, Map<Type, Type>> CACHE = new WeakConcurrentMap<>();
/** /**
* 获取泛型变量和泛型实际类型的对应关系Map * 获取泛型变量和泛型实际类型的对应关系Map

View File

@ -14,7 +14,7 @@ package org.dromara.hutool.core.reflect;
import org.dromara.hutool.core.exception.HutoolException; import org.dromara.hutool.core.exception.HutoolException;
import org.dromara.hutool.core.lang.Assert; import org.dromara.hutool.core.lang.Assert;
import org.dromara.hutool.core.map.reference.WeakKeyConcurrentMap; import org.dromara.hutool.core.map.reference.WeakConcurrentMap;
import org.dromara.hutool.core.reflect.creator.DefaultObjectCreator; import org.dromara.hutool.core.reflect.creator.DefaultObjectCreator;
import org.dromara.hutool.core.reflect.creator.PossibleObjectCreator; import org.dromara.hutool.core.reflect.creator.PossibleObjectCreator;
@ -29,7 +29,7 @@ public class ConstructorUtil {
/** /**
* 构造对象缓存 * 构造对象缓存
*/ */
private static final WeakKeyConcurrentMap<Class<?>, Constructor<?>[]> CONSTRUCTORS_CACHE = new WeakKeyConcurrentMap<>(); private static final WeakConcurrentMap<Class<?>, Constructor<?>[]> CONSTRUCTORS_CACHE = new WeakConcurrentMap<>();
// --------------------------------------------------------------------------------------------------------- Constructor // --------------------------------------------------------------------------------------------------------- Constructor
/** /**

View File

@ -13,13 +13,13 @@
package org.dromara.hutool.core.reflect; package org.dromara.hutool.core.reflect;
import org.dromara.hutool.core.annotation.Alias; import org.dromara.hutool.core.annotation.Alias;
import org.dromara.hutool.core.array.ArrayUtil;
import org.dromara.hutool.core.convert.Convert; import org.dromara.hutool.core.convert.Convert;
import org.dromara.hutool.core.exception.HutoolException; import org.dromara.hutool.core.exception.HutoolException;
import org.dromara.hutool.core.lang.Assert; import org.dromara.hutool.core.lang.Assert;
import org.dromara.hutool.core.map.MapUtil; import org.dromara.hutool.core.map.MapUtil;
import org.dromara.hutool.core.map.reference.WeakKeyConcurrentMap; import org.dromara.hutool.core.map.reference.WeakConcurrentMap;
import org.dromara.hutool.core.text.StrUtil; import org.dromara.hutool.core.text.StrUtil;
import org.dromara.hutool.core.array.ArrayUtil;
import java.lang.reflect.Field; import java.lang.reflect.Field;
import java.util.HashMap; import java.util.HashMap;
@ -36,7 +36,7 @@ public class FieldUtil {
/** /**
* 字段缓存 * 字段缓存
*/ */
private static final WeakKeyConcurrentMap<Class<?>, Field[]> FIELDS_CACHE = new WeakKeyConcurrentMap<>(); private static final WeakConcurrentMap<Class<?>, Field[]> FIELDS_CACHE = new WeakConcurrentMap<>();
// --------------------------------------------------------------------------------------------------------- Field // --------------------------------------------------------------------------------------------------------- Field

View File

@ -16,7 +16,7 @@ import org.dromara.hutool.core.array.ArrayUtil;
import org.dromara.hutool.core.lang.mutable.Mutable; import org.dromara.hutool.core.lang.mutable.Mutable;
import org.dromara.hutool.core.lang.mutable.MutableObj; import org.dromara.hutool.core.lang.mutable.MutableObj;
import org.dromara.hutool.core.map.MapUtil; import org.dromara.hutool.core.map.MapUtil;
import org.dromara.hutool.core.map.reference.WeakKeyConcurrentMap; import org.dromara.hutool.core.map.reference.WeakConcurrentMap;
import org.dromara.hutool.core.reflect.ClassUtil; import org.dromara.hutool.core.reflect.ClassUtil;
import java.lang.reflect.Method; import java.lang.reflect.Method;
@ -63,7 +63,7 @@ import java.util.function.Predicate;
* <p><strong>缓存</strong> * <p><strong>缓存</strong>
* <p>对于{@link #getDeclaredMethods}{@link #getMethods}方法与基于这两个方法实现的 * <p>对于{@link #getDeclaredMethods}{@link #getMethods}方法与基于这两个方法实现的
* 所有{@code xxxFromMethods}{@code xxxFromDeclaredMethods}方法 * 所有{@code xxxFromMethods}{@code xxxFromDeclaredMethods}方法
* 都提供了缓存基于{@link WeakKeyConcurrentMap}的缓存支持<br> * 都提供了缓存基于{@link WeakConcurrentMap}的缓存支持<br>
* {@link #getAllMethods}与所有{@code xxxFromAllMethods}方法都基于{@link #getDeclaredMethods}实现 * {@link #getAllMethods}与所有{@code xxxFromAllMethods}方法都基于{@link #getDeclaredMethods}实现
* 但是每次全量查找都需要重新遍历类层级结构因此会带来一定的额外的性能损耗<br> * 但是每次全量查找都需要重新遍历类层级结构因此会带来一定的额外的性能损耗<br>
* 缓存在GC时会被回收但是也可以通过{@link #clearCaches}手动清除缓存 * 缓存在GC时会被回收但是也可以通过{@link #clearCaches}手动清除缓存
@ -87,12 +87,12 @@ public class MethodScanner {
/** /**
* 方法缓存 * 方法缓存
*/ */
private static final WeakKeyConcurrentMap<Class<?>, Method[]> METHODS_CACHE = new WeakKeyConcurrentMap<>(); private static final WeakConcurrentMap<Class<?>, Method[]> METHODS_CACHE = new WeakConcurrentMap<>();
/** /**
* 直接声明的方法缓存 * 直接声明的方法缓存
*/ */
private static final WeakKeyConcurrentMap<Class<?>, Method[]> DECLARED_METHODS_CACHE = new WeakKeyConcurrentMap<>(); private static final WeakConcurrentMap<Class<?>, Method[]> DECLARED_METHODS_CACHE = new WeakConcurrentMap<>();
// region ============= basic ============= // region ============= basic =============

View File

@ -22,7 +22,7 @@ import org.dromara.hutool.core.exception.ExceptionUtil;
import org.dromara.hutool.core.exception.HutoolException; import org.dromara.hutool.core.exception.HutoolException;
import org.dromara.hutool.core.lang.Assert; import org.dromara.hutool.core.lang.Assert;
import org.dromara.hutool.core.lang.Singleton; import org.dromara.hutool.core.lang.Singleton;
import org.dromara.hutool.core.map.reference.WeakKeyConcurrentMap; import org.dromara.hutool.core.map.reference.WeakConcurrentMap;
import org.dromara.hutool.core.reflect.ClassUtil; import org.dromara.hutool.core.reflect.ClassUtil;
import org.dromara.hutool.core.reflect.ConstructorUtil; import org.dromara.hutool.core.reflect.ConstructorUtil;
import org.dromara.hutool.core.reflect.ModifierUtil; import org.dromara.hutool.core.reflect.ModifierUtil;
@ -44,11 +44,11 @@ public class MethodUtil {
/** /**
* 方法缓存 * 方法缓存
*/ */
private static final WeakKeyConcurrentMap<Class<?>, Method[]> METHODS_CACHE = new WeakKeyConcurrentMap<>(); private static final WeakConcurrentMap<Class<?>, Method[]> METHODS_CACHE = new WeakConcurrentMap<>();
/** /**
* 直接声明的方法缓存 * 直接声明的方法缓存
*/ */
private static final WeakKeyConcurrentMap<Class<?>, Method[]> DECLARED_METHODS_CACHE = new WeakKeyConcurrentMap<>(); private static final WeakConcurrentMap<Class<?>, Method[]> DECLARED_METHODS_CACHE = new WeakConcurrentMap<>();
// --------------------------------------------------------------------------------------------------------- method // --------------------------------------------------------------------------------------------------------- method

View File

@ -12,7 +12,7 @@
package org.dromara.hutool.core.regex; package org.dromara.hutool.core.regex;
import org.dromara.hutool.core.map.reference.WeakKeyConcurrentMap; import org.dromara.hutool.core.map.reference.WeakConcurrentMap;
import java.util.regex.Pattern; import java.util.regex.Pattern;
@ -209,7 +209,7 @@ public class PatternPool {
/** /**
* Pattern池 * Pattern池
*/ */
private static final WeakKeyConcurrentMap<RegexWithFlag, Pattern> POOL = new WeakKeyConcurrentMap<>(); private static final WeakConcurrentMap<RegexWithFlag, Pattern> POOL = new WeakConcurrentMap<>();
/** /**
* 先从Pattern池中查找正则对应的{@link Pattern}找不到则编译正则表达式并入池 * 先从Pattern池中查找正则对应的{@link Pattern}找不到则编译正则表达式并入池

View File

@ -14,7 +14,7 @@ package org.dromara.hutool.core.text.placeholder;
import org.dromara.hutool.core.array.ArrayUtil; import org.dromara.hutool.core.array.ArrayUtil;
import org.dromara.hutool.core.lang.mutable.MutableEntry; import org.dromara.hutool.core.lang.mutable.MutableEntry;
import org.dromara.hutool.core.map.reference.WeakKeyConcurrentMap; import org.dromara.hutool.core.map.reference.WeakConcurrentMap;
import org.dromara.hutool.core.text.StrUtil; import org.dromara.hutool.core.text.StrUtil;
import org.dromara.hutool.core.text.placeholder.template.NamedPlaceholderStrTemplate; import org.dromara.hutool.core.text.placeholder.template.NamedPlaceholderStrTemplate;
import org.dromara.hutool.core.text.placeholder.template.SinglePlaceholderStrTemplate; import org.dromara.hutool.core.text.placeholder.template.SinglePlaceholderStrTemplate;
@ -27,7 +27,7 @@ import java.util.Map;
* @author Looly * @author Looly
*/ */
public class StrFormatter { public class StrFormatter {
private static final WeakKeyConcurrentMap<Map.Entry<CharSequence, Object>, StrTemplate> CACHE = new WeakKeyConcurrentMap<>(); private static final WeakConcurrentMap<Map.Entry<CharSequence, Object>, StrTemplate> CACHE = new WeakConcurrentMap<>();
/** /**
* 格式化字符串<br> * 格式化字符串<br>

View File

@ -339,7 +339,7 @@ public class ObjUtil {
* @return 映射函数的结果, 如果输入对象为 null,则返回 null * @return 映射函数的结果, 如果输入对象为 null,则返回 null
*/ */
public static <T, R> R apply(final T source, final Function<T, R> handler) { public static <T, R> R apply(final T source, final Function<T, R> handler) {
return defaultIfNull(source, handler, null); return defaultIfNull(source, handler, (R)null);
} }
/** /**

View File

@ -12,7 +12,7 @@
package org.dromara.hutool.core.map; package org.dromara.hutool.core.map;
import org.dromara.hutool.core.map.reference.WeakKeyConcurrentMap; import org.dromara.hutool.core.map.reference.WeakConcurrentMap;
import org.dromara.hutool.core.thread.ConcurrencyTester; import org.dromara.hutool.core.thread.ConcurrencyTester;
import org.dromara.hutool.core.thread.ThreadUtil; import org.dromara.hutool.core.thread.ThreadUtil;
import org.dromara.hutool.core.util.ObjUtil; import org.dromara.hutool.core.util.ObjUtil;
@ -23,10 +23,9 @@ import org.junit.jupiter.api.Test;
public class WeakConcurrentMapTest { public class WeakConcurrentMapTest {
@Test @Test
public void putAndGetTest(){ public void putAndGetTest() {
final WeakKeyConcurrentMap<Object, Object> map = new WeakKeyConcurrentMap<>(); final WeakConcurrentMap<Object, Object> map = new WeakConcurrentMap<>();
Object Object key1 = new Object();
key1 = new Object();
final Object value1 = new Object(); final Object value1 = new Object();
Object key2 = new Object(); Object key2 = new Object();
final Object value2 = new Object(); final Object value2 = new Object();
@ -57,10 +56,10 @@ public class WeakConcurrentMapTest {
} }
@Test @Test
public void getConcurrencyTest(){ public void getConcurrencyTest() {
final WeakKeyConcurrentMap<String, String> cache = new WeakKeyConcurrentMap<>(); final WeakConcurrentMap<String, String> cache = new WeakConcurrentMap<>();
final ConcurrencyTester tester = new ConcurrencyTester(2000); final ConcurrencyTester tester = new ConcurrencyTester(2000);
tester.test(()-> cache.computeIfAbsent("aaa" + RandomUtil.randomInt(2), (key)-> "aaaValue")); tester.test(() -> cache.computeIfAbsent("aaa" + RandomUtil.randomInt(2), (key) -> "aaaValue"));
Assertions.assertTrue(tester.getInterval() > 0); Assertions.assertTrue(tester.getInterval() > 0);
final String value = ObjUtil.defaultIfNull(cache.get("aaa0"), cache.get("aaa1")); final String value = ObjUtil.defaultIfNull(cache.get("aaa0"), cache.get("aaa1"));

View File

@ -12,7 +12,7 @@
package org.dromara.hutool.extra.spring.cglib; package org.dromara.hutool.extra.spring.cglib;
import org.dromara.hutool.core.map.reference.WeakKeyConcurrentMap; import org.dromara.hutool.core.map.reference.WeakConcurrentMap;
import org.dromara.hutool.core.text.StrUtil; import org.dromara.hutool.core.text.StrUtil;
import org.springframework.cglib.beans.BeanCopier; import org.springframework.cglib.beans.BeanCopier;
import org.springframework.cglib.core.Converter; import org.springframework.cglib.core.Converter;
@ -30,7 +30,7 @@ public enum BeanCopierCache {
*/ */
INSTANCE; INSTANCE;
private final WeakKeyConcurrentMap<String, BeanCopier> cache = new WeakKeyConcurrentMap<>(); private final WeakConcurrentMap<String, BeanCopier> cache = new WeakConcurrentMap<>();
/** /**
* 获得类与转换器生成的key在{@link BeanCopier}的Map中对应的元素 * 获得类与转换器生成的key在{@link BeanCopier}的Map中对应的元素