使用 Java 集合进行缓存系统设计的实践分享!

全文目录:

    • 开篇语
      • 前言
      • [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. 总结)
    • 文末

开篇语

哈喽,各位小伙伴们,你们好呀,我是喵手。运营社区:C站/掘金/腾讯云/阿里云/华为云/51CTO;欢迎大家常来逛逛

今天我要给大家分享一些自己日常学习到的一些知识点,并以文字的形式跟大家一起交流,互相学习,一个人虽可以走的更快,但一群人可以走的更远。

我是一名后端开发爱好者,工作日常接触到最多的就是Java语言啦,所以我都尽量抽业余时间把自己所学到所会的,通过文章的形式进行输出,希望以这种方式帮助到更多的初学者或者想入门的小伙伴们,同时也能对自己的技术进行沉淀,加以复盘,查缺补漏。

小伙伴们在批阅的过程中,如果觉得文章不错,欢迎点赞、收藏、关注哦。三连即是对作者我写作道路上最好的鼓励与支持!

前言

在现代应用程序中,缓存是提升系统性能的关键技术之一。缓存通过减少对后端数据源(如数据库、文件系统等)的访问,显著提升系统的响应速度。Java 提供了多种方式来设计和实现缓存系统,其中使用集合类(如 LinkedHashMap)、SoftReferenceWeakReference 以及第三方库(如 Guava Cache)是实现高效缓存管理的常见方式。

本文将从缓存系统设计的角度出发,分享如何使用 Java 集合进行缓存设计,包括 LRU(Least Recently Used)缓存的实现思路、SoftReferenceWeakReference 在缓存中的作用,以及如何使用 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 在缓存中的作用

在缓存设计中,SoftReferenceWeakReference 是两种用于缓存的引用类型,它们可以帮助我们在内存不足时自动回收缓存元素,从而避免内存溢出问题。

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 缓存是一个简单而高效的设计,特别适合在缓存容量有限时,自动淘汰最不常用的元素。
  • 软引用和弱引用SoftReferenceWeakReference 提供了内存敏感型的缓存机制,适用于内存敏感的应用场景,分别用于长时间缓存和短期缓存。
  • Guava Cache :通过 Guava 的缓存管理,我们可以轻松地实现复杂的缓存策略,如过期时间、缓存大小限制、自动加载等,使缓存管理更加高效和灵活。

通过合理选择和使用这些缓存技术,我们能够显著提升应用的性能,并保证内存管理的灵活性与安全性。

... ...

文末

好啦,以上就是我这期的全部内容,如果有任何疑问,欢迎下方留言哦,咱们下期见。

... ...

学习不分先后,知识不分多少;事无巨细,当以虚心求教;三人行,必有我师焉!!!

wished for you successed !!!


⭐️若喜欢我,就请关注我叭。

⭐️若对您有用,就请点赞叭。

⭐️若有疑问,就请评论留言告诉我叭。


版权声明:本文由作者原创,转载请注明出处,谢谢支持!

相关推荐
我在北京coding2 分钟前
Uncaught (in promise) TypeError: x.isoWeek is not a function
开发语言·javascript·vue.js
showmethetime5 分钟前
[设计模式]创建型模式-单例模式
开发语言
Y1_again_0_again17 分钟前
Java 包装类详解
java·开发语言
武子康28 分钟前
Java-52 深入浅出 Tomcat SSL工作原理 性能优化 参数配置 JVM优化
java·jvm·后端·servlet·性能优化·tomcat·ssl
别骂我h40 分钟前
容器技术技术入门与Docker环境部署
java·spring cloud·docker
用户30742971671581 小时前
Spring AI Chain工作流模式完整指南
java·架构
CC大煊1 小时前
【java】@RestController和@Controller的区别
java·开发语言
Ven%1 小时前
掌握Bash脚本编写:从服务启动脚本到语法精要
linux·服务器·开发语言·chrome·bash
安全系统学习1 小时前
【网络安全】文件上传型XSS攻击解析
开发语言·python·算法·安全·web安全