物件緩衝池--採用最近最久未使用策略(LRUCache )管理物件,同時帶有事件監聽功能

yangxi_001發表於2013-11-26

1.LRUCacheWithListener :邏輯在這裡實現
 物件緩衝池---採用最近最久未使用策略管理物件,同時帶有事件監聽功能
工作原理:
採用集合框架(Java.connection包)來實現最近最久未使用物件池
首先構造物件池、設定池的大小
放置物件到池中,儲存時候,池的指標指向該物件,以表明該物件最近最短被使用過
當把新的物件放入到池中時候,池已經滿,那把刪除最久沒有被使用的物件,然後放入物件
當從池中讀取物件時候,根據條件從池中獲得物件;然後把池的指標指向該取出的物件,以表明該物件最近最短被使用過
當池中有物件被清除時候(當成垃圾清除),會觸發相關事件
當池被清空時候,會出發相關事件
這個類參考了org.apache.tomcat.util.collections.LRUCache的實現細節。
當然原始碼採用Hashtable來儲存池的物件列表,這裡採用另外的儲存方式---HashMap來儲存
org.apache.tomcat.util.collections.LRUCache
檔案位置:jakarta-tomcat-5.5.6jakarta-tomcat-connectorsutil

import Java.util.*;

public class LRUCacheWithListener {

    /**
     * 池物件的包裹類,這樣便於相關處理
     * **/
    class CacheNode {
        CacheNode prev;
        CacheNode next;
        Abandon value;
        Object key;
        public CacheNode() {
        }
    }

    /**
     * 物件池大小
     **/
    private int cacheSize;
    /**
     * 物件列表、當然可以採用泛型程式設計,這樣就實現自動裝箱、解箱(boxing/unboxing)
     * **/
    private HashMap nodes;

    /**
     * 物件池當前物件數
     * **/
    private int currentSize;
    /**
     * 第一個節點
     * **/
    private CacheNode first;
    /***
     * 最後一個節點
     * **/
    private CacheNode last;
    /**
     * 物件鎖
     * 實際上下面也就幾個地方使用了該鎖,可以用同步方法來取代調使用這個物件鎖
     * **/
    private static int DEFAULT_SIZE = 10;
    public LRUCacheWithListener() {
        this(DEFAULT_SIZE);
    }

    public LRUCacheWithListener(int poolSize) {
        cacheSize = poolSize;
        currentSize = 0;
        first = null; //
        last = null; //
        nodes = new HashMap(poolSize);
    }

    /**
     * 讀取一個物件
     * ***/
    public synchronized Object get(Object key) {
        CacheNode node = (CacheNode) nodes.get(key);
        if (node != null) {
            moveToHead(node);
            return node.value;
        } else {
            return null;
        }

    }

    /**
     * 把指定物件移動到連結串列的頭部
     * */
    private void moveToHead(CacheNode node) {
        if (node == first) {
            return;
        }
        if (node.prev != null) {
            node.prev.next = node.next;
        }
        if (node.next != null) {
            node.next.prev = node.prev;
        }
        if (last == node) {
            last = node.prev;
        }
        if (first != null) {
            node.next = first;
            first.prev = node;
        }
        first = node;
        node.prev = null;
        if (last == null) {
            last = first;
        }
    }

    /**
     * 刪除池中指定物件
     * **/
    public synchronized Object remove(Object key) {
        CacheNode node = (CacheNode) nodes.get(key);
        if (node != null) {
            if (node.prev != null) {
                node.prev.next = node.next;
            }
            if (node.next != null) {
                node.next.prev = node.prev;
            }
            if (last == node) {
                last = node.prev;
            }
            if (first == node) {
                first = node.next;
            }
        }
        return node;

    }


    /****
     * 放置一個物件到池中
     * */
    public synchronized void put(Object key, Abandon value) {

        CacheNode node = (CacheNode) nodes.get(key);
        if (node == null) {
            //池滿,刪除最久沒有使用的物件
            if (currentSize >= cacheSize) {
                if (last != null) {
                    nodes.remove(last.key);
                }
                removeLast();
            }
            //池沒有滿,直接把物件放入池中
            else {
                currentSize++;
            }
            node = getANewCacheNode();
        }
        node.value = value;
        node.key = key;
        // 把放入池的這個物件移動到連結串列的頭部,表示最近最短被使用過
        moveToHead(node);
        nodes.put(key, node);

    }

    /**清空池中物件
     * **/
    public synchronized void clear() {
//        if (first != null) {
//            Iterator i = nodes.values().iterator();
//           //觸發事件,該池已經被清空
//            CacheNode n;
//            while (i.hasNext()) {
//                n = (CacheNode) (i.next());
//                n.value.poolClear();            
//            }        
//        }
        while(!nodes.isEmpty()){
             //add by jeff
             if (last != null) {
                 nodes.remove(last.key);
             }
             removeLast(); //從池中將物件一個個移除
         }
        first = null;
        last = null;

    }

    /***
     * 獲得一個新的包裹物件
     * **/
    private CacheNode getANewCacheNode() {
        CacheNode node = new CacheNode();
        return node;
    }

    /**
     * 刪除池中最久沒有使用的物件
     * **/
    private void removeLast() {
        if (last != null) {
           //物件從池中被拋棄,觸發事件
            last.value.onAbandon();
            if (last.prev != null) {
                last.prev.next = null;
            } else {
                first = null;
            }
            last = last.prev;
        }

    }

2.Abandon :定義物件被拋棄和池被清空的事件介面

public interface Abandon {
            public void onAbandon();
}
3.CacheNodeWithListener  測試類

public class CacheNodeWithListener implements Abandon {
    int id;
    public CacheNodeWithListener() {

    }

    public CacheNodeWithListener(int i) {
        id = i;
    }

    /**
     * 當物件被池所拋棄時候,進行相關處理
     * ***/
    public void onAbandon() {
        System.out.println(this +"---onAbandon()");
    }

    public String toString() {
        return "id=" + id;
    }  

    static public void main(String[] s) {
        LRUCacheWithListener pool = new LRUCacheWithListener(3); //LRUCacheWithListener(int poolSize) 物件池大小
        int i;
        for (i = 1; i <= 5; i++) {
            pool.put("obj" + i, new CacheNodeWithListener(i));
            System.out.println("obj--"+i);
        }
         System.out.println("obj"+4+":"+pool.get("obj"+4));
        pool.clear();//把 《物件池全清空》,poolSize有多大清多少
        //檢查pool裡的物件是否全清掉
        for (i = 1; i <= 5; i++) {
          System.out.println("obj"+i+":"+pool.get("obj"+i));
        }
       
    }
}

4.結論:列印結果

 當poolSize為3,而有5個物件需要加入,列印結果如下: 
obj--1
obj--2
obj--3
id=1---onAbandon()
obj--4
id=2---onAbandon()
obj--5
obj4:id=4
id=3---onAbandon()
id=5---onAbandon()
id=4---onAbandon()
obj1:null
obj2:null
obj3:null
obj4:null
obj5:null

    解析:先放入3個物件,第四個物件加入時拋棄最先加入的物件1
    第五個物件加入時拋棄最二先加入的物件2,最後clear就把
    記憶體中的3,4,5清掉

相關文章