在某些不存在缓存中间件的系统中,需要用到缓存,大多数时候都是使用map,但是map会占jvm内存,并且不会回收,缓存量大的情况会经常出现OOM错误,这时候就可以使用java的软引用结合map一起实现缓存机制。对于java的四种引用类型:强引用,软引用,弱引用,虚引用,这里就不做详细介绍。声明一下,软引用会在发生OOM之前,回收其中的对象。下面使用软引用结合map写一个对于内存敏感的高速缓存。直接上代码
package com.*.servicecore; import java.lang.ref.Reference; import java.lang.ref.ReferenceQueue; import java.lang.ref.SoftReference; import java.util.HashMap; import java.util.Map; /** * @desc 软引用缓存,解决不存在缓存中间件情况下,使用JVM缓存导致OOM * @author ly * @date 2019-05-24 */ public class SoftReferenceCache<K,V>{ private static final int DEFAULT_MAP_SIZE = 1024; private static SoftReferenceCache softReferenceCache = new SoftReferenceCache(); private Map<K, CacheReference<K,V>> softReferenceMap = new HashMap<>(DEFAULT_MAP_SIZE); private final ReferenceQueue<V> referenceQueue; private final ObjectNotFoundHandler<K,V> objectNotFoundHandler; /** * 构造方法 * @param handler */ public SoftReferenceCache(ObjectNotFoundHandler<K, V> handler){ this.referenceQueue = new ReferenceQueue<V>(); this.objectNotFoundHandler = handler == null ? new DefaultObjectNotFoundHandler<K,V>() : handler; } /** * 无参构造方法 */ public SoftReferenceCache() { this(null); } /** * 静态工厂方法 * @return */ public static SoftReferenceCache newInstance(){ return softReferenceCache; } /** * 根据key清除对应的缓存 * @param key */ public final void clearSoftReference(K key){ //判断key对应软引用的对象是否被回收 if(this.softReferenceMap.containsKey(key) && this.softReferenceMap.get(key).get() == null){ this.softReferenceMap.remove(key); } V object = null; //如果当前Key对应的软引用的对象被回收则移除该Key Reference<? extends V> reference = null; while ((reference = this.referenceQueue.poll()) != null ){ object = reference.get(); if(object == null){ this.softReferenceMap.remove(((CacheReference<K, V>) reference).getKey()); } } } /** * 将需要缓存的数据放入缓存池 * @param key * @param reference */ public final void putSoftReference(K key,V reference){ clearSoftReference(key); if(!this.softReferenceMap.containsKey(key) || this.softReferenceMap.get(key).get() != null){ this.softReferenceMap.put(key,new CacheReference<K, V>(key,reference,this.referenceQueue)); } } /** * 根据key获取缓存池中的对象 * @param key * @return */ public final V getSoftReference(K key){ V object = null; if(this.softReferenceMap.containsKey(key)){ object = this.softReferenceMap.get(key).get(); } if(object == null){ //软引用指向的对象被回收,并缓存该软引用 object = this.objectNotFoundHandler.queryValueAndCache(); this.putSoftReference(key,object); } return object; } /** * 清空所有缓存 */ public final void clearAllObject() { this.softReferenceMap.clear(); } /** * 是否存在key对应的对象 * @param key * @return */ public final boolean containsKey(Object key) { return softReferenceMap.containsKey(key); } /** * 缓存应用类,继承软引用 * @param <K> * @param <V> */ private static class CacheReference<K,V> extends SoftReference<V>{ private final K key; public CacheReference(K key, V reference, ReferenceQueue<V> queue) { super(reference,queue); this.key = key; } public K getKey(){ return this.key; } } /** * 缓存取不到时的处理器接口 * @param <K> * @param <V> */ public interface ObjectNotFoundHandler<K,V>{ V queryValueAndCache(); } /** * 缓存中取不到时的处理器默认实现类 */ private static class DefaultObjectNotFoundHandler<K,V> implements ObjectNotFoundHandler<K,V>{ @Override public V queryValueAndCache() { //后面根据实际业务场景需要实现 return null; } } }