LRU算法
Least Recently Used 意思是最近最少使用,是一种常用的置换算法,当你向一个队列或者其他容器中添加任务或者页面时容器已满,该算法会自动清理一个位置给你,今天我实现的就是添加了过期时间同时能够自动清理过期时间的LRU算法
下面是实现和思路
package interview; import java.util.*; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ScheduledThreadPoolExecutor; import java.util.concurrent.TimeUnit; /** * @ Author :fqg * @ Date :Created in 12:12 2020/8/25 */ public class TimeOutLRU { static class Node implements Comparable<Node>{ String key; Object value; Long expireTime; public Node(){} public Node(String key, Object value, long expireTime){ this.key = key; this.value = value; this.expireTime = expireTime; } //内比较器的重写 @Override public int compareTo(Node o) { long l = this.expireTime - o.expireTime; if(l < 0) return -1; if(l > 0) return 1; return 0; } } //线程池中的worker线程 static class ExpireThread implements Runnable{ @Override public void run() { long now = System.currentTimeMillis(); while (true) { Node n = queue.peek(); if(n == null || n.expireTime > now) return; queue.remove(n); map.remove(n.key); System.out.println("清除成功"); } } } //内部容量,保证线程安全使用concurrentHashMap同时将queue设置成单例模式 private static ConcurrentHashMap<String, Node> map; //使用优先队列,在队列内将Node进行排序 private static volatile PriorityQueue<Node> queue; //线程池,这里使用定时任务线程池 private static ScheduledThreadPoolExecutor pool = new ScheduledThreadPoolExecutor(10); //双从检查锁 private PriorityQueue<Node> getInstance(){ if(queue == null){ synchronized(TimeOutLRU.class){ if(queue == null){ queue = new PriorityQueue<>(1024); } } } return queue; } //constructor public TimeOutLRU(){ map = new ConcurrentHashMap<>(); queue = getInstance(); //每隔三秒获取queue的头结点,查看是否过期。 pool.scheduleWithFixedDelay(new ExpireThread(), 0, 3, TimeUnit.SECONDS); } //expose method public Object set(String key, Object value, long time){ //获取过期时间 long timeout = System.currentTimeMillis() + time; Node newNode = new Node(key, value, timeout); Node old = map.put(key, newNode); queue.offer(newNode); if(old != null){ queue.remove(old); return old.value; } return null; } public Object get(String key){ Node n = map.get(key); return n == null ? null : n.value; } public static void main(String[] args) throws InterruptedException { TimeOutLRU timeOutLRU = new TimeOutLRU(); timeOutLRU.set("1","fqg",1000); Thread.sleep(1000); Object str = timeOutLRU.get("1"); System.out.println(str); } }
测试结果如下
问题:
1.实现思路总结
重新定义个一个Node添加过期时间字段,使用优先队列和ConcurrentHashaMap来存值和过期检测,使用定时任务线程池来循环检测优先队列的头结点是否过期,如果过期就删除(实现过程中没有实现队列满了,或者其他特殊情况,当时我想的是如果队列满了,直接删除头结点就行,因为毕竟是个优先级队列,头结点的过期时间永远是最近的)
2.Comparator和Comparable两个比较器的区别
一个在内部使用一个在外部使用,用处不同意义相同但是体现的思想不同,内比较器体现的封装,外比较器体现的扩展。