Java實現LRU緩存方案?


Java實現LRU緩存方法?

/**
* 可以使用雙向鏈表和哈希表實現一個LRU緩存
* 1、使用雙向鏈表實現的隊列,隊列的最大容量是緩存的大小。在使用的過程中,把最近使用的頁面移動到隊列頭,最近沒有使用的放到隊尾
* 2、使用一個哈希表,把頁號作為鍵,把緩存在隊列中的節點的的地址作為值
* 當引用一個頁面時,這個所需的頁面在內存中,需要把這個頁對應的節點移動到隊列的前面,並且更新在哈希表中結點的地址
* 當所需的頁面不在內存時,我們把它存儲到內存中
* 當隊列滿時,那么就從隊列尾部移除一個結點,並將新結點添加到隊列的前面
*/

package com.lru;

import java.util.HashMap;

/**
 * @ClassName LRU
 * @Description 最近最少使用
 * @Author Administrator
 * @Date 2019/5/30 20:05
 * @Version 1.0
 **/
public class LRU<K,V> {
    /**
     * 可以使用雙向鏈表和哈希表實現一個LRU緩存
     * 1、使用雙向鏈表實現的隊列,隊列的最大容量是緩存的大小。在使用的過程中,把最近使用的頁面移動到隊列頭,最近沒有使用的放到隊尾
     * 2、使用一個哈希表,把頁號作為鍵,把緩存在隊列中的節點的的地址作為值
     * 當引用一個頁面時,這個所需的頁面在內存中,需要把這個頁對應的節點移動到隊列的前面,並且更新在哈希表中結點的地址
     * 當所需的頁面不在內存時,我們把它存儲到內存中
     * 當隊列滿時,那么就從隊列尾部移除一個結點,並將新結點添加到隊列的前面
     */

    private final int MAX_CACHE_SIZE;
    private Entry first;
    private Entry last;

    private HashMap<K, Entry<K, V>> hashMap;

    /**
     *
     * @param cacheSize 初始的緩存的大小
     */
    public LRU(int cacheSize) {
        this.MAX_CACHE_SIZE = cacheSize;
        hashMap = new HashMap<K, Entry<K, V>>();
    }

    public void put(K key, V value) {
        Entry entry = getEntry(key);
        if(entry == null) {
            if(hashMap.size() >= MAX_CACHE_SIZE) {
                hashMap.remove(last.key);
                removeLast();
            }
            entry = new Entry();
            entry.key = key;
        }
        entry.value = value;
        moveToFirst(entry);
        hashMap.put(key, entry);
    }


    /**
     * 獲取key鍵對應的值
     * @param key
     * @return
     */
    public V get(K key) {
        Entry<K, V> entry = getEntry(key);
        if(entry == null) {
            return null;
        }
        // 將當前entry移動到開頭
        moveToFirst(entry);
        return entry.value;
    }

    /**
     * 將最近訪問的entry移動到開頭
     * @param entry
     */
    private void moveToFirst(Entry entry) {
        /**
         * 1、如果是第一個元素,則不需要移動
         */
        if(entry == first) {
            return;
        }

        /**
         * 2、如果entry節點的前面的節點存在,則改變前面的節點的指向
         */
        if(entry.pre != null) {
            entry.pre.next = entry.next;
        }

        /**
         * 3、如果entry節點的后面存在,則改變后面節點的前向指向
         */
        if(entry.next != null) {
            entry.next.pre = entry.pre;
        }

        /**
         * 4、如果當前結點是最后一個結點,那么該變last指向
         */
        if(entry == last) {
            last = last.pre;
        }

        /**
         * 5、
         */
        if(first == null || last == null) {
            first = last = entry;
            return ;
        }

        /**
         * 移動entry到隊頭
         */
        entry.next = first;
        first.pre = entry;
        entry.pre = null;
    }

    /**
     * 刪除
     */
    private void removeLast() {
        if(last != null) {
            last = last.pre;
            if(last == null) {
                first = null;
            } else {
                last.next = null;
            }

        }
    }

    private Entry<K, V> getEntry(K key) {
        return hashMap.get(key);
    }

    /**
     * 存儲鍵值的節點
     * @param <K>
     * @param <V>
     */
    class Entry<K, V> {
        public Entry pre;
        public Entry next;
        public K key;
        public V value;
    }
}

  

測試主類

package com.lru;

/**
 * @ClassName Main
 * @Description LRU緩存測試主類
 * @Author Administrator
 * @Date 2019/5/30 20:29
 * @Version 1.0
 **/
public class Main {

    public static void main(String[] args) {
        LRU<Integer, String> lru = new LRU<>(5);
        lru.put(1, "String1");
        lru.put(2, "String2");
        lru.put(3, "String3");
        lru.put(4, "String4");
        lru.put(5, "String5");
        lru.put(6, "String6");
        System.out.println(lru.get(1));
    }
}

  


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM