全文目录:
-
- 开篇语
-
- 前言
- [1. **LRU 缓存设计思路(LinkedHashMap 实现)**](#1. LRU 缓存设计思路(LinkedHashMap 实现))
-
- [1.1 **LinkedHashMap 实现 LRU 缓存**](#1.1 LinkedHashMap 实现 LRU 缓存)
- [1.2 **LRU 缓存的特点与应用场景**](#1.2 LRU 缓存的特点与应用场景)
- [2. **SoftReference/WeakReference 在缓存中的作用**](#2. SoftReference/WeakReference 在缓存中的作用)
-
- [2.1 **SoftReference**](#2.1 SoftReference)
- [2.2 **WeakReference**](#2.2 WeakReference)
- [2.3 **SoftReference 和 WeakReference 在缓存中的作用**](#2.3 SoftReference 和 WeakReference 在缓存中的作用)
- [3. **使用 Guava Cache 简化缓存管理**](#3. 使用 Guava Cache 简化缓存管理)
-
- [3.1 **Guava Cache 的优势**](#3.1 Guava Cache 的优势)
- [3.2 **基本使用示例**](#3.2 基本使用示例)
- [3.3 **Guava Cache 的高级特性**](#3.3 Guava Cache 的高级特性)
- [4. **总结**](#4. 总结)
- 文末
开篇语
今天我要给大家分享一些自己日常学习到的一些知识点,并以文字的形式跟大家一起交流,互相学习,一个人虽可以走的更快,但一群人可以走的更远。
我是一名后端开发爱好者,工作日常接触到最多的就是Java语言啦,所以我都尽量抽业余时间把自己所学到所会的,通过文章的形式进行输出,希望以这种方式帮助到更多的初学者或者想入门的小伙伴们,同时也能对自己的技术进行沉淀,加以复盘,查缺补漏。
小伙伴们在批阅的过程中,如果觉得文章不错,欢迎点赞、收藏、关注哦。三连即是对作者我写作道路上最好的鼓励与支持!
前言
在现代应用程序中,缓存是提升系统性能的关键技术之一。缓存通过减少对后端数据源(如数据库、文件系统等)的访问,显著提升系统的响应速度。Java 提供了多种方式来设计和实现缓存系统,其中使用集合类(如 LinkedHashMap
)、SoftReference
、WeakReference
以及第三方库(如 Guava Cache
)是实现高效缓存管理的常见方式。
本文将从缓存系统设计的角度出发,分享如何使用 Java 集合进行缓存设计,包括 LRU(Least Recently Used)缓存的实现思路、SoftReference
和 WeakReference
在缓存中的作用,以及如何使用 Guava Cache
来简化缓存管理。
1. LRU 缓存设计思路(LinkedHashMap 实现)
LRU 缓存是最常见的缓存算法之一,它的基本原理是:当缓存满时,移除最久未使用的元素。LRU 缓存通过维护一个元素的使用顺序来实现这一点。Java 的 LinkedHashMap
提供了一个方便的实现,可以让我们轻松地实现 LRU 缓存。
1.1 LinkedHashMap 实现 LRU 缓存
LinkedHashMap
是一个有序的 Map
,它通过维护元素的插入顺序或者访问顺序,允许我们在访问元素时按顺序来管理缓存的元素。为了实现 LRU 缓存,我们可以使用 LinkedHashMap
的访问顺序来自动调整元素顺序,并通过限制缓存的最大容量来淘汰最久未使用的元素。
关键步骤:
- 使用
LinkedHashMap
设置accessOrder=true
来启用按访问顺序排序。 - 重写
removeEldestEntry
方法,在缓存达到最大容量时,自动删除最久未使用的元素。
java
import java.util.LinkedHashMap;
import java.util.Map;
public class LRUCache<K, V> extends LinkedHashMap<K, V> {
private int maxSize;
public LRUCache(int maxSize) {
super(16, 0.75f, true); // 初始化 LinkedHashMap,accessOrder=true 表示按访问顺序排序
this.maxSize = maxSize;
}
@Override
protected boolean removeEldestEntry(Map.Entry<K, V> eldest) {
// 当缓存达到最大容量时,移除最久未使用的元素
return size() > maxSize;
}
public static void main(String[] args) {
LRUCache<Integer, String> cache = new LRUCache<>(3);
cache.put(1, "A");
cache.put(2, "B");
cache.put(3, "C");
System.out.println(cache); // {1=A, 2=B, 3=C}
cache.get(1); // 访问元素 1
cache.put(4, "D"); // 插入新元素,应该淘汰最久未使用的元素 2
System.out.println(cache); // {3=C, 1=A, 4=D}
}
}
1.2 LRU 缓存的特点与应用场景
- 特点:LRU 缓存通过维护元素的访问顺序,能够快速地识别最久未使用的元素,从而实现缓存的淘汰机制。
- 应用场景:LRU 缓存适用于那些数据访问具有"最近使用"的特点的场景,例如 Web 缓存、数据库连接池、图像处理中的缓存等。
2. SoftReference/WeakReference 在缓存中的作用
在缓存设计中,SoftReference
和 WeakReference
是两种用于缓存的引用类型,它们可以帮助我们在内存不足时自动回收缓存元素,从而避免内存溢出问题。
2.1 SoftReference
SoftReference
是一种软引用,当系统内存不足时,JVM 会尽量回收持有软引用的对象。软引用非常适合用于缓存,因为它可以在内存充足时保持缓存对象的引用,而在内存紧张时自动被回收。
- 应用场景:适用于需要缓存大量数据,但又不希望因缓存数据过多而导致内存溢出的场景。例如,图像缓存、网页内容缓存等。
示例:
java
import java.lang.ref.SoftReference;
public class SoftReferenceExample {
public static void main(String[] args) {
String largeObject = new String("Large Object");
SoftReference<String> softReference = new SoftReference<>(largeObject);
System.out.println("Before GC: " + softReference.get()); // Large Object
// Suggest JVM to perform garbage collection
System.gc();
System.out.println("After GC: " + softReference.get()); //可能为null
}
}
2.2 WeakReference
WeakReference
是一种弱引用,当对象仅持有弱引用时,只要进行垃圾回收,JVM 就会回收这些对象。与 SoftReference
相比,WeakReference
会更早地被回收,适用于不需要长时间缓存的数据。
- 应用场景:适用于缓存一些临时数据,这些数据不需要长时间存在,而是可以在任何时候被回收。例如,缓存对象的元数据或临时计算结果。
示例:
java
import java.lang.ref.WeakReference;
public class WeakReferenceExample {
public static void main(String[] args) {
String largeObject = new String("Temporary Object");
WeakReference<String> weakReference = new WeakReference<>(largeObject);
System.out.println("Before GC: " + weakReference.get()); // Temporary Object
// Suggest JVM to perform garbage collection
System.gc();
System.out.println("After GC: " + weakReference.get()); // 可能为null
}
}
2.3 SoftReference 和 WeakReference 在缓存中的作用
- SoftReference:适用于缓存较大且占用内存较多的对象。软引用能够在内存不足时自动释放缓存对象,因此可以有效防止内存溢出。
- WeakReference:适用于缓存一些不重要的数据对象,当内存紧张时,弱引用对象会被尽早回收,因此适合存储可以在任何时候丢弃的数据。
3. 使用 Guava Cache 简化缓存管理
Guava 是 Google 提供的一个常用 Java 库,其中的 Cache
类提供了一个非常强大且易于使用的缓存系统,能够帮助我们简化缓存管理。
3.1 Guava Cache 的优势
- 内存和时间限制:可以设置缓存的大小限制和过期时间。
- 自动回收机制:支持基于时间(如最后一次访问时间)或最大缓存项数来自动回收缓存。
- 线程安全 :
Cache
是线程安全的,可以在多线程环境中安全使用。
3.2 基本使用示例
java
import com.google.common.cache.Cache;
import com.google.common.cache.CacheBuilder;
import java.util.concurrent.TimeUnit;
public class GuavaCacheExample {
public static void main(String[] args) {
// 创建一个缓存,最大容量为 100,30 秒后过期
Cache<Integer, String> cache = CacheBuilder.newBuilder()
.maximumSize(100)
.expireAfterAccess(30, TimeUnit.SECONDS)
.build();
// 向缓存中添加元素
cache.put(1, "Value1");
cache.put(2, "Value2");
// 从缓存中获取元素
System.out.println("Cache value for key 1: " + cache.getIfPresent(1));
// 等待 31 秒后,元素应该会过期
try {
TimeUnit.SECONDS.sleep(31);
} catch (InterruptedException e) {
e.printStackTrace();
}
// 再次从缓存中获取元素
System.out.println("Cache value for key 1 after expiration: " + cache.getIfPresent(1)); // null
}
}
3.3 Guava Cache 的高级特性
- 缓存加载器 :
CacheLoader
允许我们在缓存缺失时自动加载数据。 - 缓存移除监听器:可以监听缓存项被移除的事件,并进行处理。
java
Cache<Integer, String> cache = CacheBuilder.newBuilder()
.maximumSize(100)
.removalListener(notification -> {
System.out.println("Removed: " + notification.getKey() + " = " + notification.getValue());
})
.build();
4. 总结
- LRU 缓存 :使用
LinkedHashMap
实现 LRU 缓存是一个简单而高效的设计,特别适合在缓存容量有限时,自动淘汰最不常用的元素。 - 软引用和弱引用 :
SoftReference
和WeakReference
提供了内存敏感型的缓存机制,适用于内存敏感的应用场景,分别用于长时间缓存和短期缓存。 - Guava Cache :通过
Guava
的缓存管理,我们可以轻松地实现复杂的缓存策略,如过期时间、缓存大小限制、自动加载等,使缓存管理更加高效和灵活。
通过合理选择和使用这些缓存技术,我们能够显著提升应用的性能,并保证内存管理的灵活性与安全性。
... ...
文末
好啦,以上就是我这期的全部内容,如果有任何疑问,欢迎下方留言哦,咱们下期见。
... ...
学习不分先后,知识不分多少;事无巨细,当以虚心求教;三人行,必有我师焉!!!
wished for you successed !!!
⭐️若喜欢我,就请关注我叭。
⭐️若对您有用,就请点赞叭。
⭐️若有疑问,就请评论留言告诉我叭。
版权声明:本文由作者原创,转载请注明出处,谢谢支持!