<强> Java实现LRU缓存的实例详解强>
<强> 强>
1.缓存缓存对于代码系统的加速与优化具有极大的作用,对于码农来说是一个很熟悉的概念。可以说,你在内存中新增了一个一段空间(比方说数组、列表)存放一些冗余的结果数据,并利用这些数据完成了以空间换时间的优化目的,你就已经使用了缓存。
有服务级的缓存框架,如memcache、复述等。其实,很多时候,我们在自己同一个服务内,或者单个进程内也需要缓存,例如,lucene就对搜索做了缓存,而无须依赖外界。那么,我们如何实现我们自己的缓存?还要带自动失效的,最好还是LRU(最近最少使用)。
当你思考怎么去实现,你可能会想得很远。为了LRU,需要把刚使用的数据存入栈,或者纪录每个数据最近使用的时间,再来的定时扫描失效的线程…。其实,Java本身就已经为我们提供了LRU缓存很好的实现,即LinkedHashMap。
<强> 2. linkedhashmap分析强>
很多没有去细究过其内部实现的人,只是将其当作一个普通的hashMap来对待.LinkedHashMap是一个双向链表,加上HashTable的实现。表现出来与普通hashMap的一个区别就是LinkedHashMap会记录存入其中的数据的顺序,并能按顺取出。
为了实现,一个哈希表,自然应该先申请在一片连续的内存空间上。当需要存入数据的时候,根据相应的散列值存入。而LinkedHashMap在这个基础上,为每个入口设置了之前与之后属性,形了一个双向链表,记录了他们把进入的前后顺序。
不仅如此,每当通过得到来获得某个元素后,得到方法内部,会在最后通过afterNodeAccess方法来调整链表的指向:
空白afterNodeAccess (Nodee){//移动节点 LinkedHashMap.Entry 最后一次; 如果(accessOrder,,(去年=尾)!=e) { LinkedHashMap.Entry p=(LinkedHashMap.Entry ) e、b=p。之前,一个=p.after; p。后=零; if (b==null) 头=; 其他的 b。在=; 如果(一个!=null) 一个。之前=b; 其他的 去年=b; 如果(去年==null) 头=p; 其他{ p。之前=去年; 最后一次。后=p; } 尾=p; + + modCount; } } >之前 上述代码将e节点移至了双向链表的未尾。而在方法afterNodeInsertion中,只要满足条件,便移除最老的数据,即链表的头。
空白afterNodeInsertion(布尔驱逐){//可能删除老大 LinkedHashMap.Entry第一个; 如果(驱逐,,(第一个=头)!=零,,removeEldestEntry(第一)){ K键=first.key; removeNode(散列(关键),钥匙,null,假的,真的); } } >之前 可见,当你为LinkedHashMap设置有限空间的时候,自然便完成了LRU缓存的效果。当然还有一个前提,你必须重写一个方法removeEldestEntry,返回真的。表示空间已满时,删除最老的。
@Override 公共布尔removeEldestEntry (Map.Entry老大){ 返回的大小()在能力; } >之前 <强> 3。线程安全的LRU缓存强>
如此,我们就获得了一个LRU缓存利器,满足了我们大多场景下的需求。但还有一个问题,它不是线程安全的。在多线程的情况下,你有可能需要对某些缓存做同步处理。这时候,你再找,可以看到java有ConcurrentHashMap的实现,但并不存在ConcurrentLinkedHashMap这样的类。
当然这个问题也不大,我们可以对再有的LinkedHashMap,再作封装,对get、put之类的方法加上同步操作。
目前,我们所用的处理,是直接采和谷歌提供的番石榴包,这里面就提供了我们想要的ConcurrentLinkedHashMap。这样就可以很方便地实现一个线程安全。具体代码如下:
进口java.util.Set; 进口com.googlecode.concurrentlinkedhashmap.Weighers; 进口com.googlecode.concurrentlinkedhashmap.ConcurrentLinkedHashMap; 公共类ConcurrentLRUCache{ 公共静态最终int DEFAULT_CONCURENCY_LEVEL=32; 私人最终ConcurrentLinkedHashMap 地图; 公共ConcurrentLRUCache (int能力){ 这(能力,DEFAULT_CONCURENCY_LEVEL); } 公共ConcurrentLRUCache (int, int并发){ 地图=new ConcurrentLinkedHashMap.Builder () .weigher(秤。你们;V>单例()) .initialCapacity(能力).maximumWeightedCapacity(能力) .concurrencyLevel(并发).build (); } 公共空间把(K键,V值){ 地图。put(关键字,值); } 公共V (K键){ V V=map.get(关键); 返回v; } 公共V getInternal (K键){ 返回map.get(关键); } 公共空间删除(K键){ map.remove(关键); } 公共长getCapacity () { 返回map.capacity (); } 公共空间updateCapacity (int能力){ map.setCapacity(能力); } 公共int getSize () { 返回map.size (); } 公共空间clear () { map.clear (); } 公共Set Java实现LRU缓存的实例详解