`

简单LRU算法实现缓存

    博客分类:
  • java
阅读更多
    最简单的LRU算法实现,就是利用jdk的LinkedHashMap,覆写其中的removeEldestEntry(Map.Entry)方法即可,如下所示:
java 代码
 
  1. import java.util.ArrayList;  
  2. import java.util.Collection;  
  3. import java.util.LinkedHashMap;  
  4. import java.util.concurrent.locks.Lock;  
  5. import java.util.concurrent.locks.ReentrantLock;  
  6. import java.util.Map;  
  7.   
  8.   
  9. /** 
  10.  * 类说明:利用LinkedHashMap实现简单的缓存, 必须实现removeEldestEntry方法,具体参见JDK文档 
  11.  *  
  12.  * @author dennis 
  13.  *  
  14.  * @param <K> 
  15.  * @param <V> 
  16.  */  
  17. public class LRULinkedHashMap<K, V> extends LinkedHashMap<K, V> {  
  18.     private final int maxCapacity;  
  19.   
  20.     private static final float DEFAULT_LOAD_FACTOR = 0.75f;  
  21.   
  22.     private final Lock lock = new ReentrantLock();  
  23.   
  24.     public LRULinkedHashMap(int maxCapacity) {  
  25.         super(maxCapacity, DEFAULT_LOAD_FACTOR, true);  
  26.         this.maxCapacity = maxCapacity;  
  27.     }  
  28.   
  29.     @Override  
  30.     protected boolean removeEldestEntry(java.util.Map.Entry<K, V> eldest) {  
  31.         return size() > maxCapacity;  
  32.     }  
  33.     @Override  
  34.     public boolean containsKey(Object key) {  
  35.         try {  
  36.             lock.lock();  
  37.             return super.containsKey(key);  
  38.         } finally {  
  39.             lock.unlock();  
  40.         }  
  41.     }  
  42.   
  43.       
  44.     @Override  
  45.     public V get(Object key) {  
  46.         try {  
  47.             lock.lock();  
  48.             return super.get(key);  
  49.         } finally {  
  50.             lock.unlock();  
  51.         }  
  52.     }  
  53.   
  54.     @Override  
  55.     public V put(K key, V value) {  
  56.         try {  
  57.             lock.lock();  
  58.             return super.put(key, value);  
  59.         } finally {  
  60.             lock.unlock();  
  61.         }  
  62.     }  
  63.   
  64.     public int size() {  
  65.         try {  
  66.             lock.lock();  
  67.             return super.size();  
  68.         } finally {  
  69.             lock.unlock();  
  70.         }  
  71.     }  
  72.   
  73.     public void clear() {  
  74.         try {  
  75.             lock.lock();  
  76.             super.clear();  
  77.         } finally {  
  78.             lock.unlock();  
  79.         }  
  80.     }  
  81.   
  82.     public Collection<Map.Entry<K, V>> getAll() {  
  83.         try {  
  84.             lock.lock();  
  85.             return new ArrayList<Map.Entry<K, V>>(super.entrySet());  
  86.         } finally {  
  87.             lock.unlock();  
  88.         }  
  89.     }  
  90. }  
  91.     

  如果你去看LinkedHashMap的源码可知,LRU算法是通过双向链表来实现,当某个位置被命中,通过调整链表的指向将该位置调整到头位置,新加入 的内容直接放在链表头,如此一来,最近被命中的内容就向链表头移动,需要替换时,链表最后的位置就是最近最少使用的位置。
    LRU算法还可以通过计数来实现,缓存存储的位置附带一个计数器,当命中时将计数器加1,替换时就查找计数最小的位置并替换,结合访问时间戳来实现。这种 算法比较适合缓存数据量较小的场景,显然,遍历查找计数最小位置的时间复杂度为O(n)。我实现了一个,结合了访问时间戳,当最小计数大于 MINI_ACESS时,就移除最久没有被访问的项:
java 代码
 
  1. import java.io.Serializable;  
  2. import java.util.ArrayList;  
  3. import java.util.Collection;  
  4. import java.util.HashMap;  
  5. import java.util.Iterator;  
  6. import java.util.Map;  
  7. import java.util.Set;  
  8. import java.util.concurrent.atomic.AtomicInteger;  
  9. import java.util.concurrent.atomic.AtomicLong;  
  10. import java.util.concurrent.locks.Lock;  
  11. import java.util.concurrent.locks.ReentrantLock;  
  12.   
  13. /** 
  14.  *  
  15.  * @author dennis  
  16.  * 类说明:当缓存数目不多时,才用缓存计数的传统LRU算法 
  17.  * @param <K> 
  18.  * @param <V> 
  19.  */  
  20. public class LRUCache<K, V> implements Serializable {  
  21.   
  22.     private static final int DEFAULT_CAPACITY = 100;  
  23.   
  24.     protected Map<K, ValueEntry> map;  
  25.   
  26.     private final Lock lock = new ReentrantLock();  
  27.   
  28.     private final transient int maxCapacity;  
  29.   
  30.     private static int MINI_ACCESS = 10;  
  31.   
  32.     public LRUCache() {  
  33.         this(DEFAULT_CAPACITY);  
  34.     }  
  35.   
  36.     public LRUCache(int capacity) {  
  37.         if (capacity <= 0)  
  38.             throw new RuntimeException("缓存容量不得小于0");  
  39.         this.maxCapacity = capacity;  
  40.         this.map = new HashMap<K, ValueEntry>(maxCapacity);  
  41.     }  
  42.   
  43.     public boolean ContainsKey(K key) {  
  44.         try {  
  45.             lock.lock();  
  46.             return this.map.containsKey(key);  
  47.         } finally {  
  48.             lock.unlock();  
  49.         }  
  50.     }  
  51.   
  52.     public V put(K key, V value) {  
  53.         try {  
  54.             lock.lock();  
  55.             if ((map.size() > maxCapacity - 1) && !map.containsKey(key)) {  
  56.                 // System.out.println("开始");  
  57.                 Set<Map.Entry<K, ValueEntry>> entries = this.map.entrySet();  
  58.                 removeRencentlyLeastAccess(entries);  
  59.             }  
  60.             ValueEntry valueEntry = map.put(key, new ValueEntry(value));  
  61.             if (valueEntry != null)  
  62.                 return valueEntry.value;  
  63.             else  
  64.                 return null;  
  65.         } finally {  
  66.             lock.unlock();  
  67.         }  
  68.     }  
  69.   
  70.     /** 
  71.      * 移除最近最少访问 
  72.      */  
  73.     protected void removeRencentlyLeastAccess(  
  74.             Set<Map.Entry<K, ValueEntry>> entries) {  
  75.         // 最小使用次数  
  76.         int least = 0;  
  77.         // 最久没有被访问  
  78.         long earliest = 0;  
  79.         K toBeRemovedByCount = null;  
  80.         K toBeRemovedByTime = null;  
  81.         Iterator<Map.Entry<K, ValueEntry>> it = entries.iterator();  
  82.         if (it.hasNext()) {  
  83.             Map.Entry<K, ValueEntry> valueEntry = it.next();  
  84.             least = valueEntry.getValue().count.get();  
  85.             toBeRemovedByCount = valueEntry.getKey();  
  86.             earliest = valueEntry.getValue().lastAccess.get();  
  87.             toBeRemovedByTime = valueEntry.getKey();  
  88.         }  
  89.         while (it.hasNext()) {  
  90.             Map.Entry<K, ValueEntry> valueEntry = it.next();  
  91.             if (valueEntry.getValue().count.get() < least) {  
  92.                 least = valueEntry.getValue().count.get();  
  93.                 toBeRemovedByCount = valueEntry.getKey();  
  94.             }  
  95.             if (valueEntry.getValue().lastAccess.get() < earliest) {  
  96.                 earliest = valueEntry.getValue().count.get();  
  97.                 toBeRemovedByTime = valueEntry.getKey();  
  98.             }  
  99.         }  
  100.         // System.out.println("remove:" + toBeRemoved);  
  101.         // 如果最少使用次数大于MINI_ACCESS,那么移除访问时间最早的项(也就是最久没有被访问的项)  
  102.         if (least > MINI_ACCESS) {  
  103.             map.remove(toBeRemovedByTime);  
  104.         } else {  
  105.             map.remove(toBeRemovedByCount);  
  106.         }  
  107.     }  
  108.   
  109.     public V get(K key) {  
  110.         try {  
  111.             lock.lock();  
  112.             V value = null;  
  113.             ValueEntry valueEntry = map.get(key);  
  114.             if (valueEntry != null) {  
  115.                 // 更新访问时间戳  
  116.                 valueEntry.updateLastAccess();  
  117.                 // 更新访问次数  
  118.                 valueEntry.count.incrementAndGet();  
  119.                 value = valueEntry.value;  
  120.             }  
  121.             return value;  
  122.         } finally {  
  123.             lock.unlock();  
  124.         }  
  125.     }  
  126.   
  127.     public void clear() {  
  128.         try {  
  129.             lock.lock();  
  130.             map.clear();  
  131.         } finally {  
  132.             lock.unlock();  
  133.         }  
  134.     }  
  135.   
  136.     public int size() {  
  137.         try {  
  138.             lock.lock();  
  139.             return map.size();  
  140.         } finally {  
  141.             lock.unlock();  
  142.         }  
  143.     }  
  144.   
  145.     public Collection<Map.Entry<K, V>> getAll() {  
  146.         try {  
  147.             lock.lock();  
  148.             Set<K> keys = map.keySet();  
  149.             Map<K, V> tmp = new HashMap<K, V>();  
  150.             for (K key : keys) {  
  151.                 tmp.put(key, map.get(key).value);  
  152.             }  
  153.             return new ArrayList<Map.Entry<K, V>>(tmp.entrySet());  
  154.         } finally {  
  155.             lock.unlock();  
  156.         }  
  157.     }  
  158.   
  159.     class ValueEntry implements Serializable {  
  160.         private V value;  
  161.   
  162.         private AtomicInteger count;  
  163.   
  164.         private AtomicLong lastAccess;  
  165.   
  166.         public ValueEntry(V value) {  
  167.             this.value = value;  
  168.             this.count = new AtomicInteger(0);  
  169.             lastAccess = new AtomicLong(System.nanoTime());  
  170.         }  
  171.           
  172.         public void updateLastAccess() {  
  173.             this.lastAccess.set(System.nanoTime());  
  174.         }  
  175.   
  176.     }  
  177. }  


分享到:
评论

相关推荐

    c语言实现的LRU算法

    在C语言中实现LRU算法,需要理解数据结构和算法的基础知识,以及如何在C语言中有效地管理内存。 首先,LRU算法的核心是数据结构的选择。通常使用双向链表来存储数据,因为双向链表允许我们快速地插入和删除元素,...

    实现了LRU算法的缓存

    当缓存满时,LRU算法会优先淘汰最近最少使用的数据。在这个Java实现的LRU缓存中,我们可能会看到以下几个关键知识点: 1. **数据结构的选择**: LRU缓存通常基于哈希表和双向链表实现。哈希表用于快速查找,而双向...

    Java实现LRU算法.zip

    在Java中实现LRU算法,通常会使用数据结构如HashMap或LinkedHashMap来存储页面及其访问信息。HashMap提供快速的查找操作,而LinkedHashMap则同时保持了插入顺序,这对于实现LRU至关重要,因为我们需要快速找到最近...

    东南大学操作系统实验——实现LRU算法及其近似算法

    实验内容包括实现LRU算法的两种不同变体:计数器实现和栈实现。在计数器实现中,每个页面都有一个访问计数器,每当页面被访问时,计数器增加,淘汰时选择计数最小的页面。而在栈实现中,页面按访问顺序存储在栈中,...

    LRU算法实现LRU算法实现LRU算法实现LRU算法实现LRU算法实现

    现在,实现LRU算法的主要逻辑在up_cache函数中,该函数将页面访问序列walk_sort和缓存数组cache作为输入参数。 void up_cache(Cache cache[], int walk_sort[]) { int i = 0; // i 为访问序列数组的下标 int x; ...

    LRU算法 C++实现

    LRU算法的实现通常依赖于数据结构,如哈希表和双向链表。在C++中,我们可以使用`std::unordered_map`来存储页面及其访问时间,同时使用`std::list`来维护页面的顺序。以下是一个简单的C++实现概述: ```cpp #...

    LRU算法 lru算法

    在实现LRU算法时,通常会用到数据结构如链表和哈希表。链表用于快速定位最近使用和最久未使用的页面,而哈希表用于快速查找页面。当一个页面被访问时,它会被移到链表的头部,表示最近被使用。如果链表已满,且有新...

    lru算法C语言实现

    ### LRU算法C语言实现详解 #### 一、引言 LRU(Least Recently Used,最近最少使用)算法是一种常用的数据缓存淘汰策略,在计算机科学领域应用广泛,尤其是在操作系统、数据库管理和Web服务器缓存管理等方面。本文...

    lru算法实验报告

    在实际应用中,LRU 算法常用于缓存管理和数据库系统,以优化数据的访问效率。例如,当内存不足以存放所有数据时,LRU 可以帮助决定哪些数据应该被暂时移除,以便为更重要的数据腾出空间。由于 LRU 的高效性和直观性...

    Nodejs基于LRU算法实现的缓存处理操作示例.docx

    本篇文章将深入探讨LRU算法的基本原理,并通过一个具体的Node.js实现案例来展示如何利用LRU算法进行高效的缓存管理。 #### 二、LRU算法简介 LRU算法的核心思想是当缓存空间满时,优先淘汰那些最近最久未使用的数据...

    LRU算法 java实现

    通过以上介绍,我们可以看出LRU算法在Java中的实现主要依赖于HashMap和DoublyLinkedList这两个数据结构,它们结合在一起提供了高效且灵活的缓存管理能力。在实际应用中,LRU算法广泛应用于数据库的缓存系统、操作...

    LRU 算法(c语言)

    在本篇文章中,我们将深入探讨一个基于C语言实现的LRU算法示例,该示例通过队列的形式来管理缓存中的页面,以确保能够有效地执行淘汰策略。 #### 关键知识点 ##### 1. 数据结构定义 在给定的代码片段中,作者使用...

    LRU算法LRU算法LRU算法LRU算法

    在缓存或者数据库管理系统中,LRU算法被广泛应用,因为它的实现简单且效果良好。 LRU算法的核心思想是:当内存满时,最近最少使用的数据会被优先淘汰。也就是说,如果一个数据最近被访问过,那么它在未来被访问的...

    LRU算法.zip

    LRU(Least Recently Used)算法是一种常用的页面替换算法,用于管理有限的内存资源。...通过深入研究这个LRU算法的实现,你不仅可以掌握LRU算法的工作原理,还能了解到如何在实际项目中应用和优化这种缓存策略。

    缓存淘汰算法之LRU

    LRU 算法的实现简单,但命中时需要遍历链表,找到命中的数据块索引,然后需要将数据移到头部。 4. LRU-K 算法 LRU-K 算法是为了解决 LRU 算法“缓存污染”的问题,其核心思想是将“最近使用过 1 次”的判断标准...

    15 当Buffer Pool中的缓存页不够的时候,如何基于LRU算法淘汰部分缓存.pdf

    在数据库管理系统中,Buffer Pool(缓冲...以上内容涵盖了Buffer Pool中缓存页管理的核心概念,包括LRU算法在缓存淘汰中的应用。这些知识点对于理解和优化数据库性能至关重要,是数据库管理员和开发者必须掌握的技术。

    一个LRU算法的实现

    在操作系统、数据库管理系统和缓存系统等领域,LRU算法都有广泛的应用。在这个实验设计课程中,我们将探讨LRU算法的原理和实现。 首先,我们需要理解LRU算法的核心思想。假设有一个固定大小的缓存(或内存),当新...

    Java实现简单LRU缓存算法

    这里的LRUCache类维护了一个双向链表和一个哈希表,用于实现LRU算法。具体实现细节如下: - get方法:首先在哈希表中查找对应的键值对,如果不存在,则返回-1;如果存在,则将对应的节点从双向链表中删除,并将其...

    LRU算法C语言版本

    LRU算法在实际应用中有着广泛的应用,例如在Web服务器缓存管理、数据库查询缓存、文件系统缓存等方面。理解并掌握LRU算法对于提升系统性能至关重要,因为它能够有效地减少因磁盘I/O导致的性能瓶颈。在C语言中实现LRU...

Global site tag (gtag.js) - Google Analytics