All Downloads are FREE. Search and download functionalities are using the official Maven repository.

cn.hutool.core.map.ReferenceConcurrentMap Maven / Gradle / Ivy

There is a newer version: 5.8.33
Show newest version
package cn.hutool.core.map;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.lang.func.Func0;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.ReferenceUtil;

import java.io.Serializable;
import java.lang.ref.Reference;
import java.lang.ref.ReferenceQueue;
import java.lang.ref.SoftReference;
import java.lang.ref.WeakReference;
import java.util.AbstractMap;
import java.util.Collection;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;
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实现
* 参考:jdk.management.resource.internal.WeakKeyConcurrentHashMap * * @param 键类型 * @param 值类型 * @author looly * @since 5.8.0 */ public class ReferenceConcurrentMap implements ConcurrentMap, Iterable>, Serializable { final ConcurrentMap, V> raw; private final ReferenceQueue lastQueue; private final ReferenceUtil.ReferenceType keyType; /** * 回收监听 */ private BiConsumer, V> purgeListener; // region 构造 /** * 构造 * * @param raw {@link ConcurrentMap}实现 * @param referenceType Reference类型 */ public ReferenceConcurrentMap(ConcurrentMap, V> raw, ReferenceUtil.ReferenceType referenceType) { this.raw = raw; this.keyType = referenceType; lastQueue = new ReferenceQueue<>(); } // endregion /** * 设置对象回收清除监听 * * @param purgeListener 监听函数 */ public void setPurgeListener(BiConsumer, V> purgeListener) { this.purgeListener = purgeListener; } @Override public int size() { this.purgeStaleKeys(); return this.raw.size(); } @Override public boolean isEmpty() { return 0 == size(); } @Override public V get(Object key) { this.purgeStaleKeys(); //noinspection unchecked return this.raw.get(ofKey((K) key, null)); } @Override public boolean containsKey(Object key) { this.purgeStaleKeys(); //noinspection unchecked return this.raw.containsKey(ofKey((K) key, null)); } @Override public boolean containsValue(Object value) { this.purgeStaleKeys(); return this.raw.containsValue(value); } @Override public V put(K key, V value) { this.purgeStaleKeys(); return this.raw.put(ofKey(key, this.lastQueue), value); } @Override public V putIfAbsent(K key, V value) { this.purgeStaleKeys(); return this.raw.putIfAbsent(ofKey(key, this.lastQueue), value); } @Override public void putAll(Map m) { m.forEach(this::put); } @Override public V replace(K key, V value) { this.purgeStaleKeys(); return this.raw.replace(ofKey(key, this.lastQueue), value); } @Override public boolean replace(K key, V oldValue, V newValue) { this.purgeStaleKeys(); return this.raw.replace(ofKey(key, this.lastQueue), oldValue, newValue); } @Override public void replaceAll(BiFunction function) { this.purgeStaleKeys(); this.raw.replaceAll((kWeakKey, value) -> function.apply(kWeakKey.get(), value)); } @Override public V computeIfAbsent(K key, Function mappingFunction) { this.purgeStaleKeys(); return this.raw.computeIfAbsent(ofKey(key, this.lastQueue), kWeakKey -> mappingFunction.apply(key)); } @Override public V computeIfPresent(K key, BiFunction remappingFunction) { this.purgeStaleKeys(); return this.raw.computeIfPresent(ofKey(key, this.lastQueue), (kWeakKey, value) -> remappingFunction.apply(key, value)); } /** * 从缓存中获得对象,当对象不在缓存中或已经过期返回Func0回调产生的对象 * * @param key 键 * @param supplier 如果不存在回调方法,用于生产值对象 * @return 值对象 */ public V computeIfAbsent(K key, Func0 supplier) { return computeIfAbsent(key, (keyParam) -> supplier.callWithRuntimeException()); } @Override public V remove(Object key) { this.purgeStaleKeys(); //noinspection unchecked return this.raw.remove(ofKey((K) key, null)); } @Override public boolean remove(Object key, Object value) { this.purgeStaleKeys(); //noinspection unchecked return this.raw.remove(ofKey((K) key, null), value); } @Override public void clear() { this.raw.clear(); //noinspection StatementWithEmptyBody while (lastQueue.poll() != null) ; } @Override public Set keySet() { this.purgeStaleKeys(); // TODO 非高效方式的set转换,应该返回一个view final Collection trans = CollUtil.trans(this.raw.keySet(), (reference) -> null == reference ? null : reference.get()); return new HashSet<>(trans); } @Override public Collection values() { this.purgeStaleKeys(); return this.raw.values(); } @Override public Set> 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(BiConsumer action) { this.purgeStaleKeys(); this.raw.forEach((key, value)-> action.accept(key.get(), value)); } @Override public Iterator> iterator() { return entrySet().iterator(); } @Override public V compute(K key, BiFunction remappingFunction) { this.purgeStaleKeys(); return this.raw.compute(ofKey(key, this.lastQueue), (kWeakKey, value) -> remappingFunction.apply(key, value)); } @Override public V merge(K key, V value, BiFunction remappingFunction) { this.purgeStaleKeys(); return this.raw.merge(ofKey(key, this.lastQueue), value, remappingFunction); } /** * 清除被回收的键 */ private void purgeStaleKeys() { Reference 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 ofKey(K key, ReferenceQueue queue) { switch (keyType) { case WEAK: return new WeakKey<>(key, queue); case SOFT: return new SoftKey<>(key, queue); } throw new IllegalArgumentException("Unsupported key type: " + keyType); } /** * 弱键 * * @param 键类型 */ private static class WeakKey extends WeakReference { private final int hashCode; /** * 构造 * * @param key 原始Key,不能为{@code null} * @param queue {@link ReferenceQueue} */ WeakKey(K key, ReferenceQueue queue) { super(key, queue); hashCode = key.hashCode(); } @Override public int hashCode() { return hashCode; } @Override public boolean equals(Object other) { if (other == this) { return true; } else if (other instanceof WeakKey) { return ObjectUtil.equals(((WeakKey) other).get(), get()); } return false; } } /** * 弱键 * * @param 键类型 */ private static class SoftKey extends SoftReference { private final int hashCode; /** * 构造 * * @param key 原始Key,不能为{@code null} * @param queue {@link ReferenceQueue} */ SoftKey(K key, ReferenceQueue queue) { super(key, queue); hashCode = key.hashCode(); } @Override public int hashCode() { return hashCode; } @Override public boolean equals(Object other) { if (other == this) { return true; } else if (other instanceof SoftKey) { return ObjectUtil.equals(((SoftKey) other).get(), get()); } return false; } } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy