`
liangwj72
  • 浏览: 11881 次
  • 性别: Icon_minigender_1
  • 来自: 广州
社区版块
存档分类
最新评论

最简单的LRU算法实现,线程安全的

阅读更多
LRU算法用途之广就不说了,凡是要用cache的地方都可以见到它的身影。特别是线程多,并发高,数据量大的环境下。

jdk1.5真好,在LinkedHashMap.java的源码中直接有这样的字样、“This kind of map is well-suited to building LRU caches.......The removeEldestEntry(Map.Entry) method may be overridden to impose a policy for removing stale mappings automatically when new mappings are added to the map.” 就是说自己写一下removeEldestEntry就搞定了。难为我当年自己写了一个。

以下是代码,我增加的是线程安全的代码
import java.util.LinkedHashMap;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

public class LRULinkedHashMap<K, V> extends LinkedHashMap<K, V>
{
    private final int maxCapacity;
    private static final float DEFAULT_LOAD_FACTOR = 0.75f;
    private final Lock lock = new ReentrantLock();

    public LRULinkedHashMap(int maxCapacity)
    {
        super(maxCapacity, DEFAULT_LOAD_FACTOR, true);
        this.maxCapacity = maxCapacity;
    }

    @Override
    protected boolean removeEldestEntry(java.util.Map.Entry<K, V> eldest)
    {
        return size() > maxCapacity;
    }

    @Override
    public V get(Object key)
    {
        try {
            lock.lock();
            return super.get(key);
        }
        finally {
            lock.unlock();
        }
    }

    @Override
    public V put(K key, V value)
    {
        try {
            lock.lock();
            return super.put(key, value);
        }
        finally {
            lock.unlock();
        }
    }
}

注意,只有get和put是线程安全的。

本来这贴是想放到入门论坛的,不过想了一下,要用LRU算法的,知道ReentrantLock的人好像也不能算新手了。
分享到:
评论
5 楼 liangwj72 2007-09-14  
dengyin2000 写道
你可以用jdk5的read write lock。 get操作是可以不用block get的线程的。

Lock的使用请看:http://www.javalobby.org/java/forums/t45090.html


不用ReadWriteLock是因为:LRU算法原理中,get操作一定是有写的操作的,否则没办法找到最近最少用过的节点,所以也没办法用ReadWriteLock。这也是我为什么在get和put用同一个锁的原因。
4 楼 liangwj72 2007-09-14  
liquidthinker 写道
apache commons的集合包里面有lru map的实现,之前做过一个objects cache,就是用的它,如果是jdk1.4环境,可以用这个


不用commons-collections中LRUMap的原因是:当时我看过里面的源码,和自己写的比较过,也和jdk1.5的比较过,发现还是jdk1.5中的实现方法效率高。

我看来的LRUMap是commons-collections-3.1中的。

BTW:当时自己写LRU算法时,完以后才发现commons collections中已经有了,也是挺郁闷的。
3 楼 dengyin2000 2007-09-14  
很简单  随手写写。<br/>
<br/>
<br/>
<div class='code_title'>java 代码</div>
<div class='dp-highlighter'>
<div class='bar'> </div>
<ol class='dp-j' start='1'>
    <li class='alt'><span><span> </span><span class='keyword'>import</span><span> java.util.LinkedHashMap;  </span></span></li>
    <li class=''><span><span class='keyword'>import</span><span> java.util.concurrent.locks.Lock;  </span></span></li>
    <li class='alt'><span><span class='keyword'>import</span><span> java.util.concurrent.locks.ReadWriteLock;  </span></span></li>
    <li class=''><span><span class='keyword'>import</span><span> java.util.concurrent.locks.ReentrantReadWriteLock;  </span></span></li>
    <li class='alt'><span><span class='keyword'>import</span><span> java.util.concurrent.locks.ReentrantReadWriteLock.ReadLock;  </span></span></li>
    <li class=''><span><span class='keyword'>import</span><span> java.util.concurrent.locks.ReentrantReadWriteLock.WriteLock;  </span></span></li>
    <li class='alt'><span>     </span></li>
    <li class=''><span> <span class='keyword'>public</span><span> </span><span class='keyword'>class</span><span> LRULinkedHashMap&lt;K, V&gt; </span><span class='keyword'>extends</span><span> LinkedHashMap&lt;K, V&gt;    </span></span></li>
    <li class='alt'><span> {    </span></li>
    <li class=''><span>     <span class='keyword'>private</span><span> </span><span class='keyword'>final</span><span> </span><span class='keyword'>int</span><span> maxCapacity;    </span></span></li>
    <li class='alt'><span>     <span class='keyword'>private</span><span> </span><span class='keyword'>static</span><span> </span><span class='keyword'>final</span><span> </span><span class='keyword'>float</span><span> DEFAULT_LOAD_FACTOR = </span><span class='number'>0</span><span>.75f;    </span></span></li>
    <li class=''><span>     <span class='keyword'>private</span><span> ReadWriteLock  globalLock ;  </span></span></li>
    <li class='alt'><span>     <span class='keyword'>private</span><span> Lock readLock;  </span></span></li>
    <li class=''><span>     <span class='keyword'>private</span><span> Lock writeLock;  </span></span></li>
    <li class='alt'><span>     </span></li>
    <li class=''><span>     <span class='keyword'>public</span><span> LRULinkedHashMap(</span><span class='keyword'>int</span><span> maxCapacity)    </span></span></li>
    <li class='alt'><span>     {    </span></li>
    <li class=''><span>         <span class='keyword'>super</span><span>(maxCapacity, DEFAULT_LOAD_FACTOR, </span><span class='keyword'>true</span><span>);    </span></span></li>
    <li class='alt'><span>         <span class='keyword'>this</span><span>.maxCapacity = maxCapacity;    </span></span></li>
    <li class=''><span>         globalLock  = <span class='keyword'>new</span><span> ReentrantReadWriteLock();  </span></span></li>
    <li class='alt'><span>         readLock = globalLock.readLock();  </span></li>
    <li class=''><span>         writeLock = globalLock.writeLock();  </span></li>
    <li class='alt'><span>     }    </span></li>
    <li class=''><span>     </span></li>
    <li class='alt'><span>     <span class='annotation'>@Override</span><span>    </span></span></li>
    <li class=''><span>     <span class='keyword'>protected</span><span> </span><span class='keyword'>boolean</span><span> removeEldestEntry(java.util.Map.Entry&lt;K, V&gt; eldest)    </span></span></li>
    <li class='alt'><span>     {    </span></li>
    <li class=''><span>         <span class='keyword'>return</span><span> size() &gt; maxCapacity;    </span></span></li>
    <li class='alt'><span>     }    </span></li>
    <li class=''><span>     </span></li>
    <li class='alt'><span>     <span class='annotation'>@Override</span><span>    </span></span></li>
    <li class=''><span>     <span class='keyword'>public</span><span> V get(Object key)    </span></span></li>
    <li class='alt'><span>     {    </span></li>
    <li class=''><span>         readLock.lock();  </span></li>
    <li class='alt'><span>         <span class='keyword'>try</span><span> {    </span></span></li>
    <li class=''><span>             <span class='keyword'>return</span><span> </span><span class='keyword'>super</span><span>.get(key);    </span></span></li>
    <li class='alt'><span>         }    </span></li>
    <li class=''><span>         <span class='keyword'>finally</span><span> {    </span></span></li>
    <li class='alt'><span>             readLock.unlock();    </span></li>
    <li class=''><span>         }    </span></li>
    <li class='alt'><span>     }    </span></li>
    <li class=''><span>     </span></li>
    <li class='alt'><span>     <span class='annotation'>@Override</span><span>    </span></span></li>
    <li class=''><span>     <span class='keyword'>public</span><span> V put(K key, V value)    </span></span></li>
    <li class='alt'><span>     {    </span></li>
    <li class=''><span>         writeLock.lock();  </span></li>
    <li class='alt'><span>         <span class='keyword'>try</span><span> {    </span></span></li>
    <li class=''><span>             <span class='keyword'>return</span><span> </span><span class='keyword'>super</span><span>.put(key, value);    </span></span></li>
    <li class='alt'><span>         }    </span></li>
    <li class=''><span>         <span class='keyword'>finally</span><span> {    </span></span></li>
    <li class='alt'><span>             writeLock.unlock();    </span></li>
    <li class=''><span>         }    </span></li>
    <li class='alt'><span>     }    </span></li>
    <li class=''><span> }    </span></li>
</ol>
</div>
2 楼 dengyin2000 2007-09-14  
你可以用jdk5的read write lock。 get操作是可以不用block get的线程的。

Lock的使用请看:http://www.javalobby.org/java/forums/t45090.html
1 楼 liquidthinker 2007-09-14  
apache commons的集合包里面有lru map的实现,之前做过一个objects cache,就是用的它,如果是jdk1.4环境,可以用这个

相关推荐

    用C语言的堆栈实现LRU算法

    现在我们有了一个简单的堆栈实现,接下来将它用于LRU算法。LRU算法需要维护一个大小固定的缓存,每次访问一个数据时,如果该数据在缓存中,则将其移到堆栈顶部;如果不在,且缓存未满,则将数据加入缓存并压入堆栈;...

    FIFO与LRU 算法实现(java).rar_FIFO Java_LRU_fifo

    以上代码仅为基本实现,实际应用中可能需要考虑线程安全问题,以及在`get`和`put`方法中添加异常处理等。 在提供的文档"FIFO与LRU 算法实现(java).doc"中,可能包含了具体的代码实现和分析,而"www.pudn.com.txt"...

    操作系统课设 分页式存储管理(内含OPT,FIFO,LRU,LFU四种算法,用到了线程)

    2. **先进先出法(First-In-First-Out, FIFO)**:这是最简单的页面替换策略,按照页面进入内存的顺序进行替换。尽管实现简单,但FIFO可能导致Belady's Anomaly,即增加页面替换次数,这在某些情况下违反了直观的...

    java LRU算法介绍与用法示例

    /* * 通过LinkHashMap简单实现LRU算法 */ / * 缓存大小 */ private int cacheSize; / * 当前缓存数目 */ private int currentSize; private LinkedHashMap, V&gt; maps; public LRUByHashMap(int cacheSize1) {...

    操作系统FIFO,LRU,OPT算法Java实现 无需积分/C币

    FIFO是最简单的页面替换策略,它基于队列数据结构。每当一个新的页面被请求并加载到内存中,它就被添加到队列的末尾。如果需要替换页面,系统就选择队列中最先入队的页面进行淘汰。尽管FIFO实现简单,但它的性能通常...

    java-lru-demo:这是LRU算法的实现

    在Java中,`java.util.concurrent.ConcurrentLinkedHashMap`是线程安全的LRU实现,适用于多线程环境。 **优缺点** LRU算法的优点在于其高效性和简单性,能够快速定位和移除最近最少使用的数据。然而,它也存在一定...

    操作系统 LRU页面置换算法.pdf

    LRU(Least Recently Used)页面置换算法是操作系统中处理虚拟内存管理的一种策略,它的核心思想是:当内存...此外,实际的LRU算法还会考虑到多线程环境下的并发问题,而这个简化版的示例程序并未涉及这些高级特性。

    java实现操作系统的各个置换算法

    FIFO是最简单的置换算法,按照页面进入内存的顺序进行替换。当需要换出页面时,选择最早进入内存的页面。Java中可以使用LinkedList作为数据结构来实现FIFO算法,因为它的插入和删除操作都是O(1)的时间复杂度。 4. ...

    利用c++实现页面淘汰算法

    在实现过程中,我们还需要考虑线程安全问题,特别是在多线程环境下运行时,确保数据的正确性和一致性。这可能需要使用互斥锁(mutex)或其他同步机制。 总之,通过C++实现页面淘汰算法是一项挑战性的工作,它要求...

    页面置换算法c++源码

    FIFO是最简单的页面置换算法,它按照页面进入内存的顺序进行替换,即最早进入内存的页面最早被替换出去。C++实现中,可以使用双向链表来存储页面,每当需要替换页面时,就删除链表头部的页面。 这些源码可以作为...

    操作系统 LRU

    以上代码展示了LRU算法的基本思路,但并未涵盖所有细节,例如错误处理和多线程安全。在实际应用中,还需要考虑这些因素以确保正确性和性能。这个简单的C++实现可以作为一个起点,根据具体需求进行扩展和优化。

    操作系统 页面淘汰算法

    2. **LRU(最近最少使用)算法**:LRU算法选择最近最久未使用的页面进行淘汰,因为它假设这些页面在未来最不可能被访问。此算法在实际性能上通常优于FIFO,但实现起来较为复杂。 3. **LFU(最近最不经常使用)算法*...

    Go-一个简单高效用于go的LRU缓存包

    通过阅读`lru-master`压缩包中的源代码,我们可以更深入地理解这个LRU缓存库的实现细节,包括其数据结构、算法以及如何优化性能。这将有助于我们在实际项目中更好地利用此包,提升应用程序的效率。同时,学习和研究...

    页面置换算法 操作系统

    FIFO是最简单的页面置换算法,它基于“先来的页面先被替换”的原则。当一个页面进入内存,它会被添加到一个队列的末尾。当需要替换页面时,队列的第一个页面(最早进入内存的页面)将被选择。然而,FIFO易受Belady...

    aaa.rar_FIFO LRU OPT_OPT FIFO LRU_OPT_ LRU_ FIFO_java fifo lru_l

    在设计时,需注意线程安全问题,特别是在多线程环境中,可能需要使用`synchronized`关键字或者`ConcurrentHashMap`等线程安全的数据结构。 在实际项目中,可以根据业务场景和性能需求选择合适的缓存策略。例如,...

    模拟页面置换算法

    常见的页面置换算法有FIFO(先进先出)、LRU(最近最少使用)、LFU(最不经常使用)、OPT(最佳页面置换)等。这些算法各有优缺点,例如: 1. FIFO:简单易实现,但可能导致Belady异常,即比预期更频繁地发生页面...

    PyPI 官网下载 | lru-dict-1.1.6.tar.gz

    1. **线程安全**:在多线程环境中,lru-dict提供了一种安全的方式来进行并发访问,确保了数据一致性。 2. **高性能**:通过直接操作字典的内部结构,lru-dict实现了近乎原生字典的访问速度,同时带有缓存淘汰机制。...

    LRU.rar_WORKING

    这个简单的实现提供了一种基础的LRU缓存机制,但实际应用中可能需要考虑线程安全、性能优化等更多因素。例如,可以使用`ConcurrentHashMap`代替`HashMap`以支持并发操作,或者使用`LinkedHashMap`替代自定义的链表...

    操作系统课设 页面置换算法 c#

    FIFO是最简单的页面置换算法,它的原则是当需要替换一个页面时,选择最早进入内存的页面进行淘汰。这种算法基于“先来的页面先被替换”的假设,但并不总是最优的选择,因为它可能导致Belady's异常,即增加分配的页面...

    操作系统 LUR置换算法

    在C语言中实现LUR或LRU算法,通常会涉及数据结构和算法设计。 首先,我们需要一个数据结构来存储页面及其相关信息。这通常是一个链表,每个节点代表一个页面,包含页号、访问时间戳以及指向下一个节点的指针。...

Global site tag (gtag.js) - Google Analytics