当前位置: 首页 > news >正文

Java 中 LRU 缓存机制详解与实践​

        存技术是提升系统性能的重要手段,其中 LRU(Least Recently Used,最近最少使用)缓存策略凭借其简单高效的特点,被广泛应用于各种场景。

 一、LRU 缓存策略原理

        LRU 缓存策略的核心思想是:当缓存容量已满,需要添加新元素时,移除最近最少使用的元素,为新元素腾出空间。这种策略基于一个常见的假设:近期使用过的数据,在未来被再次使用的概率较高;而长时间未使用的数据,在未来被使用的可能性较低。

二、Java 中 LRU 缓存的基础实现

         我们可以利用LinkedHashMap的特性可以快速实现一个 LRU 缓存。LinkedHashMap支持按访问顺序维护元素顺序,通过将其构造函数的accessOrder参数设为true,即可实现按访问顺序排序,实现简单的LRU机制。

import java.util.LinkedHashMap;
import java.util.Map;public class LRUCache extends LinkedHashMap<Integer, Integer> {private int capacity;public LRUCache(int capacity) {// loadFactor 设置为 0.75f,accessOrder = true 表示按照访问顺序排序super(capacity, 0.75f, true);this.capacity = capacity;}// 重写 removeEldestEntry 方法,当缓存超过容量时移除最老的条目@Overrideprotected boolean removeEldestEntry(Map.Entry<Integer, Integer> eldest) {return size() > capacity;}
}

        上述代码定义了一个LRUCache类,继承自LinkedHashMap。在构造函数中,通过super(capacity, 0.75f, true)设置了LinkedHashMap的容量、负载因子,并开启按访问顺序排序。重写的removeEldestEntry方法用于判断缓存是否超过容量,若超过则返回true,触发移除最久未使用元素的操作。这种实现方式简单直观,get和put操作的时间复杂度均为 O (1),非常适合对性能要求不高、追求代码简洁性的场景,如快速原型开发或轻量级缓存需求。

三、LRU 缓存的线程安全实现方案

        前面LRU 缓存实现可能会出现数据不一致等问题,因此需要采取措施保证线程安全。​

1. 使用Collections.synchronizedMap()包裹LinkedHashMap

import java.util.Collections;
import java.util.LinkedHashMap;
import java.util.Map;public class ThreadSafeLRUCache extends LinkedHashMap<Integer, Integer> {private final int capacity;public ThreadSafeLRUCache(int capacity) {super(capacity, 0.75f, true);this.capacity = capacity;// 使用 synchronizedMap 实现线程安全}@Overrideprotected boolean removeEldestEntry(Map.Entry<Integer, Integer> eldest) {return size() > capacity;}// 返回线程安全的 Mappublic static Map<Integer, Integer> createThreadSafeLRU(int capacity) {return Collections.synchronizedMap(new ThreadSafeLRUCache(capacity));}
}

        这种方式通过Collections.synchronizedMap对LinkedHashMap进行包裹,实现线程安全。但它是对整个 Map 加锁,性能较差,且所有方法调用都需要外部同步。

2. 手动加锁(推荐)

import java.util.LinkedHashMap;
import java.util.Map;public class ThreadSafeLRUCache {private final Map<Integer, Integer> cache;private final int capacity;private final Object lock = new Object();public ThreadSafeLRUCache(int capacity) {this.capacity = capacity;this.cache = new LinkedHashMap<Integer, Integer>(capacity, 0.75f, true) {@Overrideprotected boolean removeEldestEntry(Map.Entry<Integer, Integer> eldest) {return size() > capacity;}};}public void put(Integer key, Integer value) {synchronized (lock) {cache.put(key, value);}}public Integer get(Integer key) {synchronized (lock) {return cache.get(key);}}public Integer remove(Integer key) {synchronized (lock) {return cache.remove(key);}}
}

        手动使用ReentrantLock或synchronized关键字控制并发访问,相比synchronizedMap,其控制粒度更细,可以按需优化,更加灵活,适用于需要更精细控制的场景。

3. 使用ConcurrentHashMap + 自定义双向链表

import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentLinkedQueue;public class HighPerformanceLRUCache<K, V> {private final int capacity;private final ConcurrentHashMap<K, V> map;private final ConcurrentLinkedQueue<K> queue;public HighPerformanceLRUCache(int capacity) {this.capacity = capacity;this.map = new ConcurrentHashMap<>(capacity);this.queue = new ConcurrentLinkedQueue<>();}public V get(K key) {return map.get(key);}public void put(K key, V value) {if (map.containsKey(key)) {map.put(key, value);return;}if (map.size() >= capacity) {K eldest = queue.poll();if (eldest != null) {map.remove(eldest);}}map.put(key, value);queue.offer(key);}public void remove(K key) {map.remove(key);queue.remove(key);}
}

        使用ConcurrentHashMap和ConcurrentLinkedQueue,在高并发下具有较好的性能和可扩展性。不过,该版本为简化版,不完全等价于标准 LRU,若需完整 LRU 行为,应结合ConcurrentSkipListMap或自定义线程安全双向链表实现,适合高并发需求场景。

4. 使用第三方库(如 Caffeine、Ehcache)

import com.github.benmanes.caffeine.cache.Caffeine;
import com.github.benmanes.caffeine.cache.Cache;public class LRUCacheExample {public static void main(String[] args) {Cache<Integer, Integer> cache = Caffeine.newBuilder().maximumSize(100).build();cache.put(1, 1);System.out.println(cache.getIfPresent(1)); // 输出 1}
}

在生产环境中,推荐使用成熟的缓存库,如 Caffeine、Ehcache 等。这些库不仅实现了高性能、线程安全,还支持多种淘汰策略(大小、时间、引用类型等)。

四、总结​

不同的 LRU 缓存实现方案各有优劣,在实际开发中,我们需要根据具体需求选择合适的方案:​

  • synchronizedMap:线程安全,性能低,适用于快速原型开发。​
  • 手动加锁:线程安全,性能中等,适合对控制粒度有较高要求的场景。​
  • 自定义结构(Concurrent):线程安全,性能高,适用于高并发需求场景。​
  • 第三方库(如 Caffeine):线程安全,性能高,支持丰富功能,推荐用于生产环境。​


文章转载自:

http://1CfXCoXW.tnrdz.cn
http://TlRqgtCp.tnrdz.cn
http://Ckyzs9Pg.tnrdz.cn
http://QNGKINdI.tnrdz.cn
http://7nHiSLYU.tnrdz.cn
http://vGXnUNHy.tnrdz.cn
http://2v6FZh2E.tnrdz.cn
http://2yYRV1jt.tnrdz.cn
http://nfQSN1HN.tnrdz.cn
http://m8A0q0XB.tnrdz.cn
http://HgsdDvnA.tnrdz.cn
http://co9Ygxlw.tnrdz.cn
http://kga3DWt0.tnrdz.cn
http://21nbQTwT.tnrdz.cn
http://DFcglapF.tnrdz.cn
http://R6HaXprQ.tnrdz.cn
http://Pdcs1cjc.tnrdz.cn
http://6hfreTSX.tnrdz.cn
http://6USLnQ6z.tnrdz.cn
http://aKKeafN5.tnrdz.cn
http://djK56eKq.tnrdz.cn
http://MQERXkhb.tnrdz.cn
http://olWjYDi6.tnrdz.cn
http://0fcZAtQ3.tnrdz.cn
http://gAKeGpZI.tnrdz.cn
http://gTsazuT5.tnrdz.cn
http://ujNLNWlL.tnrdz.cn
http://eFDJ3Tew.tnrdz.cn
http://p5HHjDfJ.tnrdz.cn
http://RTKK4Tdb.tnrdz.cn
http://www.dtcms.com/a/204992.html

相关文章:

  • Linux操作系统:信号
  • 【Spring Boot】配置实战指南:Properties与YML的深度对比与最佳实践
  • C语言---内存函数
  • 【亲测有效】Ubuntu22.04安装黑屏重启进入系统卡死
  • AI赋能R-Meta分析核心技术:从热点挖掘到高级模型
  • openlayer:07点击实现切换图层之addLayer
  • 【leetcode】70. 爬楼梯
  • Java 参数值传递机制
  • 采用线性优化改进评估配电网的灵活性范围
  • docker-compose使用详解
  • Unity中SRP Batcher使用整理
  • BeamDojo: Learning Agile Humanoid Locomotion on Sparse Footholds
  • 【深度估计 Depth Estimation】数据集介绍
  • 静态方法和实例方法的区别
  • NVIDIA GPU 性能调优与诊断完全指南
  • PortgreSQL常用操作
  • shell脚本总结3
  • 网络安全管理之钓鱼演练应急预案
  • Python 训练营打卡 Day 31
  • Dirsearch 深度使用教程:从基础扫描到携带 Cookie 探索网站
  • Java—— IO流 第二期
  • PCB设计实践(二十三)什么是阻抗匹配,需要做啥
  • springboot链接nacos测试
  • 项目执行中缺乏风险管理,如何预防潜在问题?
  • 惠斯通电桥测量 数据采集模块 支持恒压/恒流的24位ADC电桥测量
  • PCB设计教程【入门篇】——电路分析基础-元件数据手册
  • 设计模式介绍
  • 解除diffusers库的prompt长度限制(SDXL版)
  • vue原生table表格实现动态添加列,一行添加完换行继续添加。el-select输入框背景颜色根据所选内容不同而改变
  • 深入解读RTP协议:RFC 3550的技术分析与应用