`

Java实现LRU缓存

    博客分类:
  • java
阅读更多

原文链接:http://quentinXXZ.iteye.com/blog/2176345

1、Cache

Cache对于代码系统的加速与优化具有极大的作用,对于码农来说是一个很熟悉的概念。可以说,你在内存中new 了一个一段空间(比方说数组,list)存放一些冗余的结果数据,并利用这些数据完成了以空间换时间的优化目的,你就已经使用了cache

有服务级的缓存框架,如memcache, redis等。其实,很多时候,我们在自己同一个服务内,或者单个进程内也需要缓存,例如,lucene就对搜索做了缓存,而无须依赖外界。那么,我们如何实现我们自己的缓存?还要带自动失效的,最好还是LRULeast Recently Used)。

 

当你思考怎么去实现,你可能会想得很远。为了LRU,需要把刚使用的数据存入栈,或者纪录每个数据最近使用的时间,再来的定时扫描失效的线程….其实,java本身就已经为我们提供了LRU Cache很好的实现,即LinkedHashMap

 

2、LinkedHashMap分析

很多没有去细究过其内部实现的人,只是将其当作一个普通的hashMap来对待。LinkedHashMap是一个双向链表,加上hashTable的实现。表现出来与普通HashMap的一个区别就是LinkedHashMap会记录存入其中的数据的顺序,并能按顺取出。

为了实现,一个hash表,自然应该先申请在一片连续的内存空间上。当需要存入数据的时候,根据相应的hash值存入。而LinkedHashMap在这个基础上,为每个entry设置了beforeafter属性,形了一个双向链表,记录了他们put进入的前后顺序。

 

不仅如此,当get每个元素后,它就会通过afterNodeAccess方法来调整链表的指向:

void afterNodeAccess(Node<K,V> e) { // move node to last
        LinkedHashMap.Entry<K,V> last;
        if (accessOrder && (last = tail) != e) {
            LinkedHashMap.Entry<K,V> p =
                (LinkedHashMap.Entry<K,V>)e, b = p.before, a = p.after;
            p.after = null;
            if (b == null)
                head = a;
            else
                b.after = a;
            if (a != null)
                a.before = b;
            else
                last = b;
            if (last == null)
                head = p;
            else {
                p.before = last;
                last.after = p;
            }
            tail = p;
            ++modCount;
        }
    }

      上述代码将Node e移至了双向链表的未尾。而在方法afterNodeInsertion中,只要满足条件,便移除最老的数据,即链表的head

void afterNodeInsertion(boolean evict) { // possibly remove eldest
        LinkedHashMap.Entry<K,V> first;
        if (evict && (first = head) != null && removeEldestEntry(first)) {
            K key = first.key;
            removeNode(hash(key), key, null, false, true);
        }
    } 

    可见,当你为linkedHashMap设置有限空间的时候,自然便完成了LRU Cache的效果。当然还有一个前提,你必须重写一个方法removeEldestEntry,返回true。表示空间已满时,删除最老的。

    @Override
    public boolean removeEldestEntry(Map.Entry<K, V> eldest){     
        return size()>capacity;        
    }

 

3、线程安全的LRU Cache

如此,我们就获得了一个LRU缓存利器,满足了我们大多场景下的需求。但还有一个问题,它不是线程安全的。在多线程的情况下,你有可能需要对某些Cache做同步处理。这时候,你再找,可以看到javaConcurrentHashMap的实现,但并不存在ConcurrentLinkedHashMap这样的类。

当然这个问题也不大,我们可以对再有的LinkedHashMap,再作封装,对getput, 之类的方法加上同步操作。

 

目前,我们所用的处理,是直接采和google提供的guava包,这里面就提供了我们想要的ConcurrentLinkedHashMap。这样就可以很方便地实现一个线程安全。具体代码如下:

import java.util.Set;

import com.googlecode.concurrentlinkedhashmap.Weighers;
import com.googlecode.concurrentlinkedhashmap.ConcurrentLinkedHashMap;

public class ConcurrentLRUCache<K, V> {
    public static final int                     DEFAULT_CONCURENCY_LEVEL = 32;

    private final ConcurrentLinkedHashMap<K, V> map;


    public ConcurrentLRUCache(int capacity) {
        this(capacity, DEFAULT_CONCURENCY_LEVEL);
    }

    public ConcurrentLRUCache(int capacity, int concurrency) {
        map = new ConcurrentLinkedHashMap.Builder<K, V>().weigher(Weighers.<V> singleton())
            .initialCapacity(capacity).maximumWeightedCapacity(capacity)
            .concurrencyLevel(concurrency).build();
    }

    public void put(K key, V value) {
        map.put(key, value);
    }

    public V get(K key) {
        V v = map.get(key);
        return v;
    }

    public V getInternal(K key) {
        return map.get(key);
    }

    public void remove(K key) {
        map.remove(key);
    }

    public long getCapacity() {
        return map.capacity();
    }


    public void updateCapacity(int capacity) {
        map.setCapacity(capacity);
    }


    public int getSize() {
        return map.size();
    }


    public void clear() {
        map.clear();
    }

    public Set<K> getKeySet() {
        return map.keySet();
    }
}

 

 

原文链接:http://quentinXXZ.iteye.com/blog/2176345

 

 

 

1
3
分享到:
评论

相关推荐

    Java实现LRU缓存机制:深入解析与高效编码实践

    在Java中实现LRU缓存机制,不仅可以帮助我们更好地理解和应用数据结构,还能在实际开发中提高程序的性能。本文将详细介绍如何在Java中实现LRU缓存机制,包括其原理、实现方式以及编码实践。 LRU缓存机制是一种非常...

    详解Java实现LRU缓存

    Java 实现 LRU 缓存 LRU 缓存是指 Least Recently Used 缓存,翻译过来就是“最近最少使用”,它是一种常用的缓存策略。 Java 实现 LRU 缓存有多种方法,本文将介绍使用 LinkedHashMap 实现 LRU 缓存的方法。 LRU ...

    Java实现LRU缓存的实例详解

    Java实现LRU缓存的实例详解 Java实现LRU缓存的实例详解是指通过Java语言实现一种高效的缓存机制,即LRU(Least Recently Used)缓存。LRU缓存是一种常用的缓存策略,其主要思想是将最近使用的数据存储在缓存中,...

    Java实现LRU算法.zip

    通过以上代码,我们已经构建了一个简单的LRU缓存系统。在实际应用中,LRU算法不仅可以用于操作系统中的页面替换,还可以应用于数据库查询缓存、编程语言的内存管理(如Java的SoftReference和WeakReference)以及Web...

    Java实现简单LRU缓存机制的方法

    Java实现简单LRU缓存机制的方法 Java实现简单LRU缓存机制的方法是指通过Java语言实现的一种缓存机制,该机制可以根据最近最少使用的原则淘汰缓存中的数据。缓存机制的实现主要是通过哈希表和双向链表来实现的。 ...

    java-leetcode题解之第146题LRU缓存.zip

    以下是简单的LRU缓存实现: ```java import java.util.HashMap; import java.util.LinkedList; import java.util.Map; public class LRUCache, V&gt; implements LRUCache, V&gt; { private int capacity; private Map...

    Java实现简单LRU缓存算法

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

    LRU算法 java实现

    以下是一个简单的LRU缓存实现的Java代码框架: ```java class LRUCache, V&gt; { private int capacity; private HashMap, Node&gt; map; private DoublyLinkedList&lt;Node&gt; list; public LRUCache(int capacity) { ...

    java实现lru

    根据提供的文件信息,我们可以深入探讨如何使用简单的数组来实现LRU(Least Recently Used,最近最少使用)缓存淘汰策略,并且解析代码中的具体实现细节。 ### LRU算法简介 LRU算法是一种常用的缓存淘汰策略,当...

    Java利用ConcurrentHashMap实现本地缓存demo

    Java利用ConcurrentHashMap实现本地缓存demo; 基本功能有缓存有效期、缓存最大数、缓存存入记录、清理线程、过期算法删除缓存、LRU算法删除、获取缓存值等功能。 复制到本地项目的时候,记得改包路径哦~

    java 缓存 cache lru 实例

    java 缓存 cache lru 实例 java 缓存 cache lru 实例 java 缓存 cache lru 实例 java 缓存 cache lru 实例 java 缓存 cache lru 实例 java 缓存 cache lru 实例 java 缓存 cache lru 实例

    浅谈Java如何实现一个基于LRU时间复杂度为O(1)的缓存

    下面是一个使用Java实现的LRU缓存示例代码: ```java public class LruCache,V&gt; { // 缓存容量 private int capacity = 2; // 缓存大小 private int size = 0; // 缓存Map private HashMap,DoubleListNode,V&gt;...

    java map 实现缓存技术

    本文将深入探讨如何使用Java Map实现缓存技术,以及其中的关键知识点。 首先,让我们理解什么是缓存。缓存是一种存储技术,用于暂时保存经常访问的数据,以便于快速检索。在Java中,我们通常使用HashMap、...

    LRU_缓存策略_LRU_缓存.zip

    Java中,可以使用`java.util.LinkedHashMap`类,通过设置`accessOrder`为`true`来实现LRU缓存。Python中,有第三方库`functools.lru_cache`提供了内置的LRU缓存功能。在C++中,可以自定义数据结构来实现LRU缓存。 ...

    实现了LRU算法的缓存

    在这个Java实现的LRU缓存中,我们可能会看到以下几个关键知识点: 1. **数据结构的选择**: LRU缓存通常基于哈希表和双向链表实现。哈希表用于快速查找,而双向链表则用来维护元素的顺序性,以便于执行删除和插入...

    LRU.rar_LRU_LRU java_lru.java

    在这个Java实现的LRU算法示例中,我们将深入探讨LRU的核心概念、如何在Java中实现以及可能的应用场景。 1. LRU算法原理: LRU算法的基本思想是:如果一个数据最近被访问过,那么将来被访问的可能性会更高。在内存...

    Lru缓存代码

    在压缩包文件`Lruch`中,可能包含了LRU缓存的具体实现代码,比如用C++、Java、Python或其他编程语言编写的LRUCache类。通过对这些代码的学习和理解,开发者可以掌握如何设计和实现自己的LRU缓存系统,从而在实际项目...

    Java和Android的Lru缓存及其实现原理

     Android提供了LRUCache类,可以方便的使用它来实现LRU算法的缓存。Java提供了LinkedHashMap,可以用该类很方便的实现LRU算法,Java的LRULinkedHashMap是直接继承了LinkedHashMap,进行了极少的改动后可以实现LRU...

    缓存淘汰算法之LRU

    LRU 算法的实现最常见的是使用一个链表保存缓存数据。详细算法实现如下: 1. 新数据插入到链表头部; 2. 每当缓存命中(即缓存数据被访问),则将数据移到链表头部; 3. 当链表满的时候,将链表尾部的数据丢弃。 3...

Global site tag (gtag.js) - Google Analytics