<rt id="bn8ez"></rt>
<label id="bn8ez"></label>

  • <span id="bn8ez"></span>

    <label id="bn8ez"><meter id="bn8ez"></meter></label>

    posts - 156,  comments - 601,  trackbacks - 0

    本文通過對Apache Commons Collections 項目中LRUMap這個集合類的源代碼進行詳細解讀,為幫助大家更好的了解這個集合類的實現原理以及使用如何該集合類。

    首先介紹一下LRU算法. LRU是由Least Recently Used的首字母組成,表示最近最少使用的含義,一般使用在對象淘汰算法上。也是比較常見的一種淘汰算法。

     

    LRUMap 則是實現的LRP算法的Map集合類,它繼承于AbstractLinkedMap 抽象類。LRUMap的使用說明如下:

    LRUMap的初始化時需要指定最大集合元素個數,新增的元素個數大于允許的最大集合個數時,則會執行LRU淘汰算法。所有的元素在LRUMap中會根據最近使用情況進行排序。最近使用的會放在元素的最前面(LRUMap是通過鏈表來存儲元素內容). 所以LRUMap進行淘汰時只需要刪除鏈表最后一個即可(即header.after所指的元素對象)

    那么那些操作會影響元素的使用情況:

    1.       put 當新增加一個集合元素對象,則表示該對象是最近被訪問的

    2.       get 操作會把當前訪問的元素對象作為最近被訪問的,會被移到鏈接表頭

    注:當執行containsKeycontainsValue操作時,不會影響元素的訪問情況。

                   LRUMap也是非線程安全。在多線程下使用可通過 Collections.synchronizedMap(Map)操作來保證線程安全。

     

    LRUMap的一個簡單使用示例:

        public static void main(String[] args) {

           

            LRUMap lruMap = new LRUMap(2);

           

            lruMap.put("a1", "1");

            lruMap.put("a2", "2");

            lruMap.get("a1");//mark as recent used

            lruMap.put("a3", "3");

            System.out.println(lruMap);

        }

                   上面的示例,當增加”a3”值時,會淘汰最近最少使用的”a2”, 最后輸出的結果為:

                                       {a1=1, a3=3}

     

    下面根據LRUMap的源碼來解讀一下LRUMap的實現原理

    整體類圖


    LRUMap類的關鍵代碼說明如下:

    1.       get操作

        public Object get(Object key) {

            LinkEntry entry = (LinkEntry) getEntry(key);

            if (entry == null) {

                return null;

            }

            moveToMRU(entry); //執行LRU操作

            return entry.getValue();

    }

    moveToMRU方法代碼如下:

        protected void moveToMRU(LinkEntry entry) {

            if (entry.after != header) {

                modCount++;

                // remove 從鏈接中移除當前節點

                entry.before.after = entry.after;

                entry.after.before = entry.before;

                // add first 把節點增加到鏈接頭部

                entry.after = header;

                entry.before = header.before;

                header.before.after = entry;

                header.before = entry;

            } else if (entry == header) {

                throw new IllegalStateException("Can't move header to MRU" +

                    " (please report this to commons-dev@jakarta.apache.org)");

            }

        }

    2.       put新增操作

      由于繼承的AbstractLinkedMap,所以put操作會調用addMapping 方法,完整代碼如下:

        protected void addMapping(int hashIndex, int hashCode, Object key, Object value) {

            if (isFull()) {

                LinkEntry reuse = header.after;

                boolean removeLRUEntry = false;

                if (scanUntilRemovable) {

                    while (reuse != header && reuse != null) {

                        if (removeLRU(reuse)) {

                            removeLRUEntry = true;

                            break;

                        }

                        reuse = reuse.after;

                    }

                    if (reuse == null) {

                        throw new IllegalStateException(

                            "Entry.after=null, header.after" + header.after + " header.before" + header.before +

                            " key=" + key + " value=" + value + " size=" + size + " maxSize=" + maxSize +

                            " Please check that your keys are immutable, and that you have used synchronization properly." +

                            " If so, then please report this to commons-dev@jakarta.apache.org as a bug.");

                    }

                } else {

                    removeLRUEntry = removeLRU(reuse);

                }

               

                if (removeLRUEntry) {

                    if (reuse == null) {

                        throw new IllegalStateException(

                            "reuse=null, header.after=" + header.after + " header.before" + header.before +

                             " key=" + key + " value=" + value + " size=" + size + " maxSize=" + maxSize +

                             " Please check that your keys are immutable, and that you have used synchronization properly." +

                             " If so, then please report this to commons-dev@jakarta.apache.org as a bug.");

                    }

                    reuseMapping(reuse, hashIndex, hashCode, key, value);

                } else {

                    super.addMapping(hashIndex, hashCode, key, value);

                }

            } else {

                super.addMapping(hashIndex, hashCode, key, value);

            }

        }

              當集合的個數超過指定的最大個數時,會調用 reuseMapping函數,把要刪除的對象的keyvalue更新為新加入的值,并再次加入到鏈接表中,并重新排定次序。

    reuseMapping函數代碼如下:

        protected void reuseMapping(LinkEntry entry, int hashIndex, int hashCode, Object key, Object value) {

            // find the entry before the entry specified in the hash table

            // remember that the parameters (except the first) refer to the new entry,

            // not the old one

            try {

                int removeIndex = hashIndex(entry.hashCode, data.length);

                HashEntry[] tmp = data// may protect against some sync issues

                HashEntry loop = tmp[removeIndex];

                HashEntry previous = null;

                while (loop != entry && loop != null) {

                    previous = loop;

                    loop = loop.next;

                }

                if (loop == null) {

                    throw new IllegalStateException(

                        "Entry.next=null, data[removeIndex]=" + data[removeIndex] + " previous=" + previous +

                        " key=" + key + " value=" + value + " size=" + size + " maxSize=" + maxSize +

                        " Please check that your keys are immutable, and that you have used synchronization properly." +

                        " If so, then please report this to commons-dev@jakarta.apache.org as a bug.");

                }

               

                // reuse the entry

                modCount++;

                removeEntry(entry, removeIndex, previous);

                reuseEntry(entry, hashIndex, hashCode, key, value);

                addEntry(entry, hashIndex);

            } catch (NullPointerException ex) {

                throw new IllegalStateException(

                        "NPE, entry=" + entry + " entryIsHeader=" + (entry==header) +

                        " key=" + key + " value=" + value + " size=" + size + " maxSize=" + maxSize +

                        " Please check that your keys are immutable, and that you have used synchronization properly." +

                        " If so, then please report this to commons-dev@jakarta.apache.org as a bug.");

            }

        }

        上面的代碼中:

              removeEntry 方法是刪除最近最少使用的節點在鏈接中的引用

        reuseEntry方法則把該節點的keyvalue賦新加入的節點的keyvalue

        addEntry 方法則把該節點加入到鏈接表,并保障相關的鏈接順序

        /**

         * Adds an entry into this map, maintaining insertion order.

         * <p>

         * This implementation adds the entry to the data storage table and

        * to the end of the linked list.

         *

         * @param entry the entry to add

         * @param hashIndex the index into the data array to store at

         */

        protected void addEntry(HashEntry entry, int hashIndex) {

            LinkEntry link = (LinkEntry) entry;

            link.after = header;

            link.before = header.before;

            header.before.after = link;

            header.before = link;

            data[hashIndex] = entry;

     }

           LRUMap的主要源碼實現就解讀到這里,實現思路還是比較好理解的。

    LRUMap的使用場景會比較多,例如可以很方便的幫我們實現基于內存的 LRU 緩存服務實現。



    Good Luck!
    Yours Matthew!

    posted on 2012-06-28 13:34 x.matthew 閱讀(5855) 評論(1)  編輯  收藏 所屬分類: Best Practise(JDK API)
    主站蜘蛛池模板: 中文字幕av无码不卡免费| 精品无码一级毛片免费视频观看| 日韩人妻无码免费视频一区二区三区| 日韩在线观看免费| 亚洲高清专区日韩精品| 在线观看免费高清视频| 国产午夜精品理论片免费观看| 亚洲人成伊人成综合网久久| 俄罗斯极品美女毛片免费播放| 蜜桃成人无码区免费视频网站| MM1313亚洲国产精品| 亚洲AV无码成人精品区天堂 | 亚洲黄色免费电影| 国产精品亚洲色图| 内射少妇36P亚洲区| 国产乱子伦精品免费女| 37pao成人国产永久免费视频| 免费人成在线观看播放a| 亚洲精品韩国美女在线| 久久亚洲色一区二区三区| 色婷婷7777免费视频在线观看| 国产在线观看xxxx免费| 久久人午夜亚洲精品无码区| 亚洲图片一区二区| 亚洲无码黄色网址| 国外成人免费高清激情视频| 久久不见久久见免费视频7| 免费人成在线观看播放a| 在线观看亚洲AV日韩A∨| 久久亚洲熟女cc98cm| 好看的亚洲黄色经典| 亚洲国产黄在线观看| 夫妻免费无码V看片| 95免费观看体验区视频| 日本道免费精品一区二区| 白白色免费在线视频| 亚洲精品乱码久久久久蜜桃| 亚洲国产成人久久77| 亚洲午夜未满十八勿入| 久久亚洲中文字幕精品一区| 免费v片在线观看无遮挡|