Redis:缓存被我写满了,该怎么办 |
您所在的位置:网站首页 › nas存满了怎么办 › Redis:缓存被我写满了,该怎么办 |
public void remove(ListNode node) { node.pre.next = node.next; node.next.pre = node.pre; } public void addLast(ListNode node) { node.pre = tail.pre; tail.pre = node; node.pre.next = node; node.next = tail; } public ListNode removeFirst() { if (head.next == tail) { return null; } ListNode first = head.next; remove(first); return first; } } 封装一个缓存类,提供最基本的get和put方法。「需要注意,这两种基本的方法都涉及到对两种数据结构的修改」。 public class MyLruCache { private int capacity; private DoubleList doubleList; private Map map; public MyLruCache(int capacity) { this.capacity = capacity; map = new HashMap(); doubleList = new DoubleList(); } public V get(Object key) { ListNode node = map.get(key); if (node == null) { return null; } // 先删除该节点,再接到尾部 doubleList.remove(node); doubleList.addLast(node); return node.value; } public void put(K key, V value) { // 直接调用这边的get方法,如果存在,它会在get内部被移动到尾巴,不用再移动一遍,直接修改值即可 if ((get(key)) != null) { map.get(key).value = value; return; } // 如果超出容量,把头去掉 if (map.size() == capacity) { ListNode listNode = doubleList.removeFirst(); map.remove(listNode.key); } // 若不存在,new一个出来 ListNode node = new ListNode(key, value); map.put(key, node); doubleList.addLast(node); } } 这里我们的实现为最近访问的放在链表的尾节点,不经常访问的放在链表的头节点 测试一波,输出为链表的正序输出(代码为了简洁没有贴toString方法) MyLruCache myLruCache = new MyLruCache(3); // {5 : 5} myLruCache.put(“5”, “5”); // {5 : 5}{3 : 3} myLruCache.put(“3”, “3”); // {5 : 5}{3 : 3}{4 : 4} myLruCache.put(“4”, “4”); // {3 : 3}{4 : 4}{2 : 2} myLruCache.put(“2”, “2”); // {4 : 4}{2 : 2}{3 : 3} myLruCache.get(“3”); 「因为LinkedHashMap的底层实现就是哈希表加双向链表,所以你可以用LinkedHashMap替换HashMap和DoubleList来改写一下上面的类」。 我来演示一下更骚的操作,只需要重写一个构造函数和removeEldestEntry方法即可。 使用LinkedHashMap实现LRU ======================== public class LruCache extends LinkedHashMap { private int cacheSize; public LruCache(int cacheSize) { /** * initialCapacity: 初始容量大小 * loadFactor: 负载因子 * accessOrder: false基于插入排序(默认),true基于访问排序 */ super(cacheSize, 0.75f, true); this.cacheSize = cacheSize; } /** * 当调用put或者putAll方法时会调用如下方法,是否删除最老的数据,默认为false */ @Override protected boolean removeEldestEntry(Map.Entry eldest) { return size() > cacheSize; } } 注意这个缓存并不是线程安全的,可以调用Collections.synchronizedMap方法返回线程安全的map LruCache lruCache = new LruCache(3); Map safeMap = Collections.synchronizedMap(lruCache); Collections.synchronizedMap实现线程安全的方式很简单,只是返回一个代理类。代理类对Map接口的所有方法加锁 public static Map synchronizedMap(Map m) { return new SynchronizedMap(m); } LFU算法 ========= 「LRU算法有一个问题,当一个长时间不被访问的key,偶尔被访问一下后,可能会造成一个比这个key访问更频繁的key被淘汰。」 即LRU算法对key的冷热程度的判断可能不准确。而LFU算法(Least Frequently Used,最不经常使用)则是按照访问频率来判断key的冷热程度的,每次删除的是一段时间内访问频率较低的数据,比LRU算法更准确。 使用3个hash表实现lfu算法 ==================== 那么我们应该如何组织数据呢? 为了实现键值的对快速访问,用一个map来保存键值对 private HashMap keyToFreq; 还需要用一个map来保存键的访问频率 private HashMap keyToFreq; 「当然你也可以把值和访问频率封装到一个类中,用一个map来替代上述的2个map」 接下来就是最核心的部分,删除访问频率最低的数据。 为了能在O(1)时间复杂度内找到访问频率最低的数据,我们需要一个变量minFreq记录访问最低的频率 自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。深知大多数Java工程师,想要提升技能,往往是自己摸索成长或者是报班学习,但对于培训机构动则几千的学费,着实压力不小。自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前! 因此收集整理了一份《2024年Java开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。 既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上Java开发知识点,真正体系化! 由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且会持续更新! 如果你觉得这些内容对你有帮助,可以扫码获取!!(备注Java获取) ![]() 就写到这了,也算是给这段时间的面试做一个总结,查漏补缺,祝自己好运吧,也希望正在求职或者打算跳槽的 程序员看到这个文章能有一点点帮助或收获,我就心满意足了。多思考,多问为什么。希望小伙伴们早点收到满意的offer! 越努力越幸运! 金九银十已经过了,就目前国内的面试模式来讲,在面试前积极的准备面试,复习整个 Java 知识体系将变得非常重要,可以很负责任的说一句,复习准备的是否充分,将直接影响你入职的成功率。但很多小伙伴却苦于没有合适的资料来回顾整个 Java 知识体系,或者有的小伙伴可能都不知道该从哪里开始复习。我偶然得到一份整理的资料,不论是从整个 Java 知识体系,还是从面试的角度来看,都是一份含技术量很高的资料。 《一线大厂Java面试题解析+核心总结学习笔记+最新讲解视频+实战项目源码》,点击传送门即可获取! 的offer! 越努力越幸运!** 金九银十已经过了,就目前国内的面试模式来讲,在面试前积极的准备面试,复习整个 Java 知识体系将变得非常重要,可以很负责任的说一句,复习准备的是否充分,将直接影响你入职的成功率。但很多小伙伴却苦于没有合适的资料来回顾整个 Java 知识体系,或者有的小伙伴可能都不知道该从哪里开始复习。我偶然得到一份整理的资料,不论是从整个 Java 知识体系,还是从面试的角度来看,都是一份含技术量很高的资料。 [外链图片转存中…(img-OQfu8dQI-1711810396346)] 《一线大厂Java面试题解析+核心总结学习笔记+最新讲解视频+实战项目源码》,点击传送门即可获取! |
CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3 |