This commit is contained in:
Looly 2022-04-17 17:56:53 +08:00
parent 7bd5aaab7c
commit c57ecead27
3 changed files with 24 additions and 6 deletions

View File

@ -1,7 +1,12 @@
package cn.hutool.cache.impl; package cn.hutool.cache.impl;
import cn.hutool.cache.CacheListener;
import cn.hutool.core.lang.Opt;
import cn.hutool.core.lang.mutable.Mutable;
import cn.hutool.core.map.WeakConcurrentMap; import cn.hutool.core.map.WeakConcurrentMap;
import java.lang.ref.Reference;
/** /**
* 弱引用缓存<br> * 弱引用缓存<br>
* 对于一个给定的键其映射的存在并不阻止垃圾回收器对该键的丢弃这就使该键成为可终止的被终止然后被回收<br> * 对于一个给定的键其映射的存在并不阻止垃圾回收器对该键的丢弃这就使该键成为可终止的被终止然后被回收<br>
@ -24,4 +29,15 @@ public class WeakCache<K, V> extends TimedCache<K, V>{
public WeakCache(long timeout) { public WeakCache(long timeout) {
super(timeout, new WeakConcurrentMap<>()); super(timeout, new WeakConcurrentMap<>());
} }
@Override
public WeakCache<K, V> setListener(CacheListener<K, V> listener) {
super.setListener(listener);
final WeakConcurrentMap<Mutable<K>, CacheObj<K, V>> map = (WeakConcurrentMap<Mutable<K>, CacheObj<K, V>>) this.cacheMap;
// WeakKey回收之后key对应的值已经是null了因此此处的key也为null
map.setPurgeListener((key, value)-> listener.onRemove(Opt.ofNullable(key).map(Reference::get).map(Mutable::get).get(), value.getValue()));
return this;
}
} }

View File

@ -26,11 +26,13 @@ public class WeakCacheTest {
@Ignore @Ignore
public void removeByGcTest(){ public void removeByGcTest(){
// https://gitee.com/dromara/hutool/issues/I51O7M // https://gitee.com/dromara/hutool/issues/I51O7M
// 经过GC
WeakCache<String, String> cache = new WeakCache<>(-1); WeakCache<String, String> cache = new WeakCache<>(-1);
cache.put("a", "1"); cache.put("a", "1");
cache.put("b", "2"); cache.put("b", "2");
// 监听
Assert.assertEquals(2, cache.size()); Assert.assertEquals(2, cache.size());
cache.setListener(Console::log);
// GC测试 // GC测试
int i=0; int i=0;

View File

@ -2,7 +2,6 @@ package cn.hutool.core.map;
import cn.hutool.core.collection.CollUtil; import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.lang.func.Func0; import cn.hutool.core.lang.func.Func0;
import cn.hutool.core.lang.func.VoidFunc1;
import cn.hutool.core.util.ObjectUtil; import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.ReferenceUtil; import cn.hutool.core.util.ReferenceUtil;
@ -40,7 +39,7 @@ public class ReferenceConcurrentMap<K, V> implements ConcurrentMap<K, V>, Iterab
/** /**
* 回收监听 * 回收监听
*/ */
private VoidFunc1<Reference<? extends K>> purgeListener; private BiConsumer<Reference<? extends K>, V> purgeListener;
// region 构造 // region 构造
@ -62,7 +61,7 @@ public class ReferenceConcurrentMap<K, V> implements ConcurrentMap<K, V>, Iterab
* *
* @param purgeListener 监听函数 * @param purgeListener 监听函数
*/ */
public void setPurgeListener(VoidFunc1<Reference<? extends K>> purgeListener) { public void setPurgeListener(BiConsumer<Reference<? extends K>, V> purgeListener) {
this.purgeListener = purgeListener; this.purgeListener = purgeListener;
} }
@ -225,10 +224,11 @@ public class ReferenceConcurrentMap<K, V> implements ConcurrentMap<K, V>, Iterab
*/ */
private void purgeStaleKeys() { private void purgeStaleKeys() {
Reference<? extends K> reference; Reference<? extends K> reference;
V value;
while ((reference = this.lastQueue.poll()) != null) { while ((reference = this.lastQueue.poll()) != null) {
this.raw.remove(reference); value = this.raw.remove(reference);
if (null != purgeListener) { if (null != purgeListener) {
purgeListener.callWithRuntimeException(reference); purgeListener.accept(reference, value);
} }
} }
} }