用LinkedHashMap實現LRU算法


(在學習操作系統時,要做一份有關LRU和clock算法的實驗報告,很多同學都應該是通過數組去實現LRU,可能是對堆棧的使用和鏈表的使用不是很熟悉吧,在網上查資料時看到了LinkedHashMap,於是自己試着用它去實現了LRU.)

LRU算法介紹:

       LRU是Least Recently Used 近期最少使用算法。內存管理的一種頁面置換算法,對於在內存中但又不用的數據快(內存塊)叫做LRU,Oracle會根據那些數據屬於LRU而將其移出內存而騰出空間來加載另外的數據,一般用於大數據處理的時候很少使用的數據那么就直接請求數據庫,如果經常請求的數據就直接在緩存里面讀取。

      最近最久未使用(LRU)的頁面置換算法,是根據頁面調入內存后的使用情況進行決策的。由於無法預測各頁面將來的使用情況,只能利用“最近的過去”作為“最近的將來”的近似,因此,LRU置換算法是選擇最近最久未使用的頁面予以淘汰。該算法賦予每個頁面一個訪問字段,用來記錄一個頁面自上次被訪問以來所經歷的時間t,當須淘汰一個頁面時,選擇現有頁面中其t值最大的,即最近最久未使用的頁面予以淘汰(可以使用這種方法去實現)。

 

LRU的實現

       可利用一個來保存當前使用的各個頁面的頁面號。每當進程訪問某頁面時,便將該頁面的頁面號從棧中移出,將它壓入棧頂。因此,棧頂始終是最新被訪問頁面的編號,而棧底則是最近最久未使用頁面的頁面號

     LRU算法也可以過雙向鏈表來實現,而LinkedHashMap恰好是通過雙向鏈表實現的java集合類,它的一大特點是,以當某個位置被命中,它就會通過調整鏈表的指向,將該位置調整到頭位置,新加入的內容直接放在鏈表頭,如此一來,最近被命中的內容就向鏈表頭移動,需要替換時,鏈表最后的位置就是最近最少使用的位置。

 假定現有一進程所訪問的頁面序列為:

4,7,0,7,1,0,1,2,1,2,6

隨着進程的訪問,棧中頁面號的變化情況如圖所示。在訪問頁面6時發生了缺頁,此時頁面4是最近最久未被訪問的頁,應將它置換出去。

clip_image002

代碼如下:

package 作業;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Scanner;
import java.util.Set;


/*LRU是Least Recently Used 近期最少使用算法。
 *通過HashLiekedMap實現LRU的算法的關鍵是,如果map里面的元素個數大於了緩存最大容量,則刪除鏈表頭元素
 */

/*public LinkedHashMap(int initialCapacity,float loadFactor,boolean accessOrder)
 *LRU參數參數:
 *initialCapacity - 初始容量。
 *loadFactor - 加載因子(需要是按該因子擴充容量)。
 *accessOrder - 排序模式( true) - 對於訪問順序(get一個元素后,這個元素被加到最后,使用了LRU  最近最少被使用的調度算法),對於插入順序,則為 false,可以不斷加入元素。
 */

 /*相關思路介紹:
  * 當有一個新的元素加入到鏈表里面時,程序會調用LinkedHahMap類中Entry的addEntry方法,
  *而該方法又會 會調用removeEldestEntry方法,這里就是實現LRU元素過期機制的地方,
  * 默認的情況下removeEldestEntry方法只返回false,表示可以一直表鏈表里面增加元素,在這個里  *修改一下就好了。 
  *
  */
 
/*
測試數據:
5
11
4 7 0 7 1 0 1 2 1 2 6
*/

import java.util.*;
public class LRULinkedHashMap<K,V> extends LinkedHashMap<K,V>{     
    private int capacity;                     //初始內存容量
    
    LRULinkedHashMap(int capacity){          //構造方法,傳入一個參數
        super(16,0.75f,true);               //調用LinkedHashMap,傳入參數    
        this.capacity=capacity;             //傳遞指定的最大內存容量
    }
    @Override
    public boolean removeEldestEntry(Map.Entry<K, V> eldest){     
        //,每加入一個元素,就判斷是size是否超過了已定的容量
        System.out.println("此時的size大小="+size());
        if((size()>capacity))
        {
            System.out.println("超出已定的內存容量,把鏈表頂端元素移除:"+eldest.getValue());
        }
        return size()>capacity;        
    }
    
    public static void main(String[] args) throws Exception{
        Scanner cin = new Scanner(System.in);
        
        System.out.println("請輸入總共內存頁面數: ");
        int n = cin.nextInt();
        Map<Integer,Integer> map=new LRULinkedHashMap<Integer, Integer>(n);
        
        System.out.println("請輸入按順序輸入要訪問內存的總共頁面數: ");
        int y = cin.nextInt();
        
        System.out.println("請輸入按順序輸入訪問內存的頁面序列: ");
        for(int i=1;i<=y;i++)
        {
            int x = cin.nextInt();
            map.put(x,  x);  
        }
        System.out.println("此時內存中包含的頁面數是有:");
        //用for-each語句,遍歷此時內存中的頁面並輸出
        for(java.util.Map.Entry<Integer, Integer> entry: map.entrySet()){
            System.out.println(entry.getValue());
        }
    }
}

實驗截圖:

image


免責聲明!

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



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