当前位置: 首页 > 科技观察

LRU缓存算法的Java自定义实现

时间:2023-03-12 10:30:18 科技观察

背景LinkedHashMap继承自HashMap,内部提供了一个removeEldestEntry方法,这是实现LRU策略的关键。HashMap还为LinkedHashMap提供了三个专用的回调方法,afterNodeAccess、AfterNodeInsertion、afterNodeRemoval,这三个方法的字面意思很容易理解,即节点访问、节点插入、节点删除后执行的行为。基于以上行为LinkedHashMap可以实现一个LRUCache的功能。关于LinkedHashMap的elderest:elderest字面意思是最老的。LinkedHashMap中有一个字段叫accessOrder。当accessOrder为true时,表示LinkedHashMap内部节点按照访问次数排序。最旧的节点也是访问最少的节点。当accessOrder为false时,表示LinkedHashMap内部节点按照插入顺序排序,最老的节点也是最早插入的节点。默认值为假。自己实现LRUCache,只需要重写removeEldestEntry方法即可。代码如下:privatestaticclassLRUCacheextendsLinkedHashMap{privatestaticfinallongserialVersionUID=-9111855653176630846L;私有静态INTMAX_ELEMENTS;publicintLRUCacheinitCap,intmaxSize)抛出IllegalArgumentException{super(initCap,0.75f,true);如果(maxSize<0)抛出新的IllegalArgumentException();MAX_ELEMENTS=最大尺寸;}@OverrideprotectedbooleanremoveEldestEntry(Map.Entryelderest){returnsize()>MAX_ELEMENTS;}}上面的代码需要一个MAX_ELEMENTS变量来限制最大存储节点数。插入节点时,判断当前节点数超过此值,则根据LRU策略使用访问最少的节点删除,这里需要注意,默认的LinkedHashMap保证了插入顺序,即就是,节点是按照插入顺序排序的,所以即使删除,也会删除插入最多的节点,但是我们在构造函数中传入了一个true,这个参数决定了LinkedHashMap内部的节点如何排序。当参数为true时,内部节点按照最近访问时间排序,为false时,内部节点按照插入顺序排序。至此,一个简单的LRUCache实现就完成了。注意LinkedHahsMap的实现本身并不是线程安全的,也就是说这个LRUCache也不是线程安全的。如果你想要多线程访问,你可以这样使用:LRUCachecache=Collections.synchronizedMap(newLRUCache(10,10))。这样缓存可以在多线程下进行get/put等操作,但是这样获取的缓存在多线程遍历时还是不安全的。所以在多线程下无法遍历缓存。官方文档也推荐在遍历同步地图时使用地图本身进行同步。