zoukankan      html  css  js  c++  java
  • 闲来无事,用Java的软引用写了一个山寨的缓存

    闲来无事,用Java的软引用写了一个山寨的缓存

    博客分类:
    • java基础
    众所周知java中的引用分为 StrongReference、SoftReference、WeakReference、PhantomReference。这几种引用有不同那个的 使用场景,平时我们用的最频繁的也就是StrongReference也就是说形如之这样的引用:

    Object obj = new Object();

      这种引用就是所谓的强引用,如果此对象没有引用指向它,并且活着的线程无法访问到它(针对垃圾孤岛而言),那么他才会被回收,如果该对象被强引用指向,并且内存被耗尽,抛出OOM垃圾收集器也不会回收该对象。

    而对于SoftReference而言它被GC回收的条件就没 那么严格了,如果一个对象当前最强的引用是软引用,并且JVM的内存充足,垃圾回收器是不会回收的该对象的。只有在内存比较吃紧的情况下GC才会回收被软 引用指向的对象,从这个特点我们就看出了软引用可以用来做一些高速缓存,配合LRU策略更好。今天我就自己写一个玩玩。

    Java代码  收藏代码
    1. 代码如下:  
    Java代码  收藏代码
    /* 
     @author blackbeans
     *  
     * 背景知识: 
     *          而对于SoftReference而言它被GC回收的条件就没那么严格了, 
     *          如果一个对象当前最强的引用是软引用,并且JVM的内存充足, 
     *          垃圾回收器是不会回收的该对象的。只有在内存比较吃紧的情况下GC才会回收被软引用指向的对象, 
     *          从这个特点我们就看出了软引用可以用来做一些高速缓存,配合LRU策略更好。今天我就自己写一个玩玩。 
     *  
     *          而对于SoftReference而言它被GC回收的条件就没那么严格了, 
     *          如果一个对象当前最强的引用是软引用,并且JVM的内存充足, 
     *          垃圾回收器是不会回收的该对象的。 
     *          只有在内存比较吃紧的情况下GC才会回收被软引用指向的对象, 
     *          从这个特点我们就看出了软引用可以用来做一些高速缓存,配合LRU策略更好。 
     *  
     */
    public class ReferenceCache<K, T> {
    
        private HashMap<K, InnerReference<K, T>> cachedReference = new HashMap<K, InnerReference<K, T>>(1024);
    
        private final ReferenceQueue<T> referenceQueue;
    
        private final ObjectNotFoundHandler<K, T> existsHandler;
    
        ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
        /**
         * 缓存中取不到时的处理器 接口
         *
         * @author blackbeans
         *
         * @param <K>
         * @param <T>
         */
        public static interface ObjectNotFoundHandler<K, T> {
    
            public T queryAndCached(K key);
        }
    
        /**
         * 默认缓存中取不到时的处理器 实现类
         *
         * @author blackbeans
         *
         * @param <K>
         * @param <T>
         */
        private static class DefaultObjectNotFoundHandler<K, T> implements ObjectNotFoundHandler<K, T> {
    
            @Override
            public T queryAndCached(K key) {
                return null;
            }
    
        }
    
        ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
        /**
         * 继承软引用
         *
         * @param <K>
         * @param <T>
         */
        private static class InnerReference<K, T> extends SoftReference<T> {
    
            private final K key;
    
            public InnerReference(K key, T reference, ReferenceQueue<T> queue) {
                super(reference, queue);
                this.key = key;
            }
    
            public K getKey() {
                return this.key;
            }
        }
    
        ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
        /**
         * 本类构造方法
         *
         * @param handler
         */
        public ReferenceCache(ObjectNotFoundHandler<K, T> handler) {
            this.referenceQueue = new ReferenceQueue<T>();
            this.existsHandler = handler == null ? new DefaultObjectNotFoundHandler<K, T>() : handler;
        }
    
        public ReferenceCache() {
            this(null);
        }
    
        /**
         * 清除给定key的缓存
         *
         * @param key
         */
        @SuppressWarnings("unchecked")
        private void cleanReference(K key) {
            //优先检查key对应软引用的对象是否被回收     
            if (this.cachedReference.containsKey(key) && this.cachedReference.get(key).get() == null) {
                this.cachedReference.remove(key);
            }
            T obj = null;
            //如果当前Key对应的软引用的对象被回收则移除该Key     
            Reference<? extends T> reference = null;
            while ((reference = this.referenceQueue.poll()) != null) {
                obj = reference.get();
                if (obj == null) {
                    this.cachedReference.remove(((InnerReference<K, T>) reference).getKey());
                }
            }
        }
    
        /**
         * 把需要缓存的数据放入缓存池
         *
         * @param key
         * @param reference
         */
        public void put(K key, T reference) {//cachedReference
            /**
             * 清除被软引用的对象并已经被回收的reference
             */
            cleanReference(key);
            if (!this.cachedReference.containsKey(key)) {
                this.cachedReference.put(key, new InnerReference<K, T>(key, reference, this.referenceQueue));
            }
        }
    
        /**
         * 获取缓存池内的换成对象
         *
         * @param key
         * @return
         */
        public T get(K key) {//getReference
    
            T obj = null;
    
            if (this.cachedReference.containsKey(key)) {
                obj = this.cachedReference.get(key).get();
            }
    
            if (null == obj) {
                /**
                 * 软引用指向的对象被回收,并缓存该软引用
                 */
                obj = this.existsHandler.queryAndCached(key);
                this.put(key, obj);
                return obj;
            }
            return obj;
    
        }
    
        /**
         * 清空所有缓存
         */
        public void clearALLObject() {
            this.cachedReference.clear();
            System.gc();
        }
    
        public boolean containsKey(Object key) {
            return cachedReference.containsKey(key);
        }
    
        public static void main(String[] args) {
            ReferenceCache cache = new ReferenceCache();
            cache.put("11", new SiteBean());
            System.out.println(cache.get("11"));
            cache.cleanReference("11");
            cache.clearALLObject();
        }
     

       在整个实现中通过将对象的引用放入我定义的一个 key->软引用map中,然后每次从cache中获取对象时,首先通过key去查询map获得对象的软引用,若存在则通过软引用去尝试获取对象, 若不存在,软引用指向的对象被回收,那么我们就回去调用内置的handler,重新生成一个对象,并cache该对象的软引用。

    在我的实现中我为用户提供了一个当对象被回收时的处理handler,企图来指导用户通过这个handler来重新构造对象,缓存对象,灵活性还是挺大的。

    不足之处就是,如果软引用的缓存能用LRU策略更完美了,再为 LRU提供一个Processor,用于用户自定义LRU策略。其实很简单只要将HashMap换成LinkedHashMap去实现 removeEldest方法,并在方法中调用自定义的LRU处理器就OK了。

            为了减少开销,我在每次cache的时候才去清理已经失效的软引用。也许有人会问为啥有个ReferenceQueue呢?其实是这样的,在软引用所引用 的对象被回收以后,试想想对象软引用的对象是被回收了,但是你又引入了另一个对象SoftReference,带走一个难道还要再留下一个,所以不会的, 软引用对象被回收后,这个软引用本身被添加到了这个queue,等待回收。通过便利这个queue获取软引用来一出map中过期的软引用。

    至此,该说的也都说了,不该说的也说了,结尾很突兀,敬请见谅!

    转载:http://blackbeans.iteye.com/blog/1039464

  • 相关阅读:
    移动端(H5)弹框组件--简单--实用--不依赖jQuery
    jquery attr()和prop()方法的区别
    jQuery选择器
    Tomcat&Web程序结构&Http协议(一)
    Javascript&DOM(三)
    html&CSS代码篇(二)
    html&css入门篇(一)
    『一本通』区间DP
    『P1549』棋盘问题
    『USACO08OCT]』Watering Hole
  • 原文地址:https://www.cnblogs.com/langtianya/p/4383175.html
Copyright © 2011-2022 走看看