详细介绍:性能优化 - 案例篇:缓存_Guava#LoadingCache设计

news/2025/10/5 10:37:15/文章来源:https://www.cnblogs.com/ljbguanli/p/19126345

详细介绍:性能优化 - 案例篇:缓存_Guava#LoadingCache设计

在这里插入图片描述


Pre

性能优化 - 理论篇:常见指标及切入点

性能优化 - 理论篇:性能优化的七类技术手段

性能优化 - 理论篇:CPU、内存、I/O诊断手段

性能优化 - 工具篇:常用的性能测试工具

性能优化 - 工具篇:基准测试 JMH

性能优化 - 案例篇:缓冲区


  1. 引言:解释缓存与缓冲的区别及缓存在性能优化中的重要性;
  2. 缓存基本概念:缓存的本质、应用场景、进程内 vs 进程外缓存;
  3. Guava LoadingCache(LC)示例:
    3.1 引入依赖与初始化配置;
    3.2 手动 put 与自动加载(CacheLoader)模式;
    3.3 缓存容量、初始大小与并发级别设置;
    3.4 缓存移除与监听(invalidate + removalListener);
  4. 缓存回收策略:
    4.1 基于容量的回收(LRU);
    4.2 基于时间的回收(expireAfterWrite / expireAfterAccess);
    4.3 基于 JVM GC 的回收(weakKeys / weakValues / softValues);
    4.4 GC 回收引发的缓存颠簸问题与解决思路;
  5. 缓存算法简述:FIFO、LRU、LFU 三种常见策略;
  6. 用 LinkedHashMap 实现简易 LRU:
    6.1 LinkedHashMap 构造参数与访问顺序;
    6.2 覆盖 removeEldestEntry 实现容量控制;
    6.3 线程安全与功能局限性说明;
  7. 操作系统层面的预读与文件缓存:readahead 机制、完全加载策略;
  8. 缓存优化一般思路:何时用缓存、容量与命中率考量;
  9. 缓存的一些注意事项与示例:HTTP 304、CDN;

引言

在性能优化 - 案例篇:缓冲区中,介绍了“缓冲”这一优化手段——通过将数据暂存到内存缓冲区,批量顺序读写来缓解设备间的速度差异。与缓冲相伴随的“孪生兄弟”就是缓存(Cache)。缓存将常用数据放到相对高速的存储层(如内存)中,从而在后续访问时实现瞬时读取,显著提升性能。

举例而言:

缓存几乎是软件中最常见的优化技术。从 CPU L1/L2/L3 缓存到 Redis、Memcached 这样的分布式缓存,无不围绕“速度差异协调”这一核心展开。

接下来我们主要聚焦于进程内缓存——堆内缓存,以 GuavaLoadingCache 为示例讲解堆内缓存设计思路、常见回收策略和算法实现。


1. 缓存基本概念

缓存的核心作用,是在两个速度差异巨大的组件之间增加一层高速存储:

根据缓存所在的物理位置,可将其分为:

  1. 进程内缓存(堆内缓存):直接存放在 JVM 堆里,访问速度最快,但容量受限于可用堆内存;
  2. 进程外缓存(进程间或分布式缓存):如 Redis、Memcached,通常运行在独立进程或集群里,通过网络访问,虽然速度比数据库快许多,但仍比堆内缓存慢一个数量级;

接下来重点讲解 进程内缓存,常见实现包括 Guava Cache、Caffeine、Ehcache、JCache 等。它们都提供了基于内存分片、高并发访问、灵活回收策略和统计监控的堆内缓存解决方案。

在这里插入图片描述


2. Guava 的 LoadingCache

在这里插入图片描述

Guava 提供了功能强大的 Cache 接口和 LoadingCache 实现,既支持手动存入(put()),也支持在缓存未命中时“自动加载”(CacheLoader)。下面通过示例逐步介绍其用法与内部配置要点。

2.1 引入依赖与初始化

首先,通过 Maven 将 Guava 库加入项目:

<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
<version>29.0-jre</version>
</dependency>

然后,使用 CacheBuilder 来创建一个 LoadingCache

LoadingCache<
String
, String> lc = CacheBuilder
.newBuilder(
)
// 设置最大缓存容量:达到上限后回收其他元素
.maximumSize(1000
)
// 设置初始容量:底层 Hash 表的初始大小为 16(默认)
.initialCapacity(16
)
// 设置并发级别:将缓存分片成 4 个 segment,提升并发读写性能
.concurrencyLevel(4
)
.build(
new CacheLoader<
String
, String>(
) {
@Override
public String load(String key)
throws Exception {
// 缓存未命中时,自动调用 slowMethod 从外部数据源加载
return slowMethod(key)
;
}
}
)
;
  • maximumSize(int):指定 缓存中可保留条目的最大数量,一旦超过,将根据回收策略(默认 LRU)移除旧元素;
  • initialCapacity(int):指定底层哈希表初始大小(bucket 数量),避免在缓存初始化时反复扩容;
  • concurrencyLevel(int):指定并发写的“分段”数,Guava 会将内部数据结构拆分为 concurrencyLevel 个部分,以减少并发冲突;

2.2 手动 put 与自动加载(CacheLoader)

LoadingCache 支持两种获取方式:

  1. 手动 put()

    lc.put("key1"
    , "value1"
    )
    ;
    String v = lc.getIfPresent("key1"
    )
    ;
    // 立即返回 "value1"

    在这种模式下,开发者负责将外部数据同步写入缓存。

  2. 自动加载 get()

在这里插入图片描述

// 第一次调用:缓存中无 key "a",触发 CacheLoader.load("a")
long start = System.nanoTime(
)
;
String result1 = lc.get("a"
)
;
// slowMethod("a") 需 1s
System.out.println("第一次调用耗时: " + (System.nanoTime(
) - start)
)
;
// 第二次调用:缓存命中,迅速返回
long start2 = System.nanoTime(
)
;
String result2 = lc.get("a"
)
;
System.out.println("第二次调用耗时: " + (System.nanoTime(
) - start2)
)
;

其中 load(String key) 方法可同步加载所需数据(如从数据库或外部 API 拉取),并在返回值后自动存入缓存。

2.2.1 示例代码

public
class GuavaCacheDemo {
// 模拟一个缓慢方法:睡眠 1 秒后返回结果
static String slowMethod(String key)
throws Exception {
Thread.sleep(1000
)
;
return key + ".result"
;
}
public
static
void main(String[] args)
throws Exception {
LoadingCache<
String
, String> lc = CacheBuilder
.newBuilder(
)
.maximumSize(1000
)
.initialCapacity(16
)
.concurrencyLevel(4
)
.recordStats(
) // 开启统计信息收集
.build(
new CacheLoader<
String
, String>(
) {
@Override
public String load(String key)
throws Exception {
return slowMethod(key)
;
}
}
)
;
// 第一次 get,会调用 slowMethod
long t1 = System.nanoTime(
)
;
String v1 = lc.get("a"
)
;
long elapsed1 = System.nanoTime(
) - t1;
System.out.println("第一次 get 用时: " + elapsed1 + " ns"
)
;
// 第二次 get,立即返回
long t2 = System.nanoTime(
)
;
String v2 = lc.get("a"
)
;
long elapsed2 = System.nanoTime(
) - t2;
System.out.println("第二次 get 用时: " + elapsed2 + " ns"
)
;
// 输出命中率与加载次数等统计
System.out.println("Cache Stats: " + lc.stats(
)
)
;
}
}
  • recordStats():开启缓存统计功能,可用于后续分析 hitRate()loadSuccessCount() 等指标;
  • CacheLoader.load():当 key 未命中时,自动调用并将结果写回缓存;

2.3 缓存移除与监听(invalidate + removalListener)


3. 缓存回收策略

在缓存容量有限的前提下,需设计合适的回收策略来剔除“冷”或不再需要的数据,以保证“热点”数据得到优先保留。Guava 原生支持多种回收方式:

3.1 基于容量的回收(LRU)


3.2 基于时间的回收


3.3 基于 JVM GC 的回收

3.3.1 GC 回收引发的缓存颠簸问题

当缓存条目使用弱引用或软引用,一旦 JVM 触发 GC,就可能一次性清空大批缓存数据。若该缓存频繁被访问,缓存将被迅速重新加载,导致连续触发多次 GC 和缓存“哗啦啦回补”的现象——CPU 消耗骤增,却无法留住数据。

解决思路


4. 常见缓存算法简介

在这里插入图片描述

除了 Guava 提供的默认 LRU,缓存领域常见还有两种算法:

4.1 FIFO(先进先出)

4.2 LRU(最近最少使用)

4.3 LFU(最近最不常用)


5. 简易 LRU 实现——LinkedHashMap

在 Java 中,要实现一个轻量级的 LRU 缓存,最便捷的方式是利用 LinkedHashMap 提供的“访问顺序”功能:

public
class LRUCache<
K
, V>
extends LinkedHashMap<
K
, V> {
private
final
int capacity;
public LRUCache(
int capacity) {
// 初始容量 16,负载因子 0.75,accessOrder=true 表示按访问顺序排列
super(16
, 0.75f
, true
)
;
this.capacity = capacity;
}
// 当 put 后,自动调用此方法判断是否需要移除最老条目
@Override
protected
boolean removeEldestEntry(Map.Entry<
K
, V> eldest) {
return size(
) > capacity;
}
}
  • 构造参数说明

    • initialCapacity:初始哈希表桶数,默认 16;
    • loadFactor:负载因子(0.75f);
    • accessOrder=true:按照“访问顺序”保持双向链表;
  • removeEldestEntry:在每次 put() 后自动调用,若返回 true,则移除“最久未访问”者,即 LRU 算法的核心。

在这里插入图片描述

5.1 功能局限与线程安全


6. 操作系统层面的预读与文件缓存

在这里插入图片描述

在操作系统层面,对文件 I/O 缓存设计也非常智能,进一步支撑了高性能缓存架构。Linux 下可以通过 free 命令查看内存状态,其中 cached 区域往往十分庞大:

$ free -h
total        used        free      shared  buff/cache   available
Mem:           16Gi       4.2Gi       2.5Gi       128Mi       9.4Gi       11Gi
Swap:         2.0Gi       512Mi       1.5Gi
  • buff/cache:表示操作系统将磁盘块缓存在内存中的容量,包括文件系统页缓存、目录缓存等;
  • Readahead(预读):当进程顺序读取文件时,内核会自动尝试以“页面”为单位预读后续若干页面,以减少随机读时的磁盘寻道开销。
    在这里插入图片描述

例如,若应用以 4KB 为单位读取大型文件,内核可能在后台提前载入 128KB 或更多连续页面,由此实现“顺序读取性能≈内存读取性能”的效果。

  • 完全加载策略:若某一小文件(如几 MB)访问频率极高,可在应用启动时一次将整个文件 mmap()read() 到内存(posix_fadvise(..., POSIX_FADV_WILLNEED)),确保后续访问都命中内核缓存;

7. 缓存优化的一般思路

在实际项目中,引入进程内缓存时,可根据以下几个准则:

  1. 缓存目标场景

  2. 缓存大小与容量

在这里插入图片描述

  1. 回收策略选择

  2. 监控与统计

  3. 缓存失效与一致性

  4. 预加载 vs 惰性加载


8. 缓存应用案例

  1. HTTP 304(Not Modified)缓存

  2. CDN(内容分发网络)缓存

  3. 数据库二级缓存


9. 小结

进程内缓存(堆内缓存) 的设计思路与常见实现:

  1. 缓存本质与应用场景

  2. Guava LoadingCache

  3. 常见缓存算法

  4. 简易 LRU 实现

  5. 操作系统缓存与预读

  6. 缓存优化一般思路

  7. 示例应用

在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/928135.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

2025年X射线管厂家最新企业品牌推荐排行榜,工业用金属陶瓷,波长色散荧光分析,应力衍射分析,管板角焊缝,轮胎检测,辐照,固定阳极波纹陶瓷,测厚,食品检测 X 射线管公司推荐

在工业无损检测领域,X 射线管作为核心元件,其质量与性能直接影响检测结果的准确性和可靠性,对国防、石油、电力、汽车零部件等关键行业的发展至关重要。当前,市场上 X 射线管厂家数量众多,产品质量参差不齐,部分…

AtCoder Beginner Contest 400

AT_abc400_d [ABC400D] Takahashi the Wall Breaker 一次踢两步也转移一下,直接搜 E - Ringos Favorite Numbers 3

网站托管服务方案网站建设办公软件销售技巧

目录 1、进程的虚拟内存分区与小于0x10000的小地址内存区 1.1、进程的虚拟内存分区 1.2、小于0x10000的小地址内存区 2、保存线程上下文的CONTEXT结构体 3、从汇编代码角度去理解多线程运行过程的典型实例 4、调用TerminateThread强制结束线程会导致线程中的资源没有释放…

2025 年北京档案存放公司 升职猫档案服务平台:16 年老牌机构的合规服务与高效解决方案解析

档案管理作为衔接个人发展与社会管理的关键环节,其规范性与便捷性直接影响考公、考研、落户、评职称等重要人生节点。随着 2025 年档案管理服务市场规模迈向 2000 亿元,数字化转型与异地办事需求持续升温,政策推动下…

设计一个企业网站大概多少钱创新的南昌网站制作

一、结构体 结构体(struct)可以理解为用户自定义的特殊的复合的“数据类型”&#xff1b; 1. 结构体变量的定义和初始化 定义结构体变量的方式&#xff1a; 先声明结构体类型再定义变量名 在声明类型的同时定义变量 // 结构体类型的定义 struct stu {char name[50];int age;…

完整教程:⼤模型驱动的DeepInsight Copilot在蚂蚁的技术实践

完整教程:⼤模型驱动的DeepInsight Copilot在蚂蚁的技术实践pre { white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important; display: block !important; font-family: "Cons…

没有网站可以做百度直通车吗自己主机做网站服务器吗

0x01 产品简介 企语iFair协同管理系统是一款专业的协同办公软件,该管理系统兼容性强,适合多种企业类型。该软件永久免费,绿色安全,无需收取费用即可使用所有功能。企语iFair协同管理系统同时兼容了Linux、Windows两种操作系统 0x02 漏洞概述 企语iFair协同管理系统getup…

[免费]微信小代码网上花店系统(SpringBoot后端+Vue管理端)【论文+源码+SQL脚本】

pre { white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important; display: block !important; font-family: "Consolas", "Monaco", "Courier New", …

2025电容厂家最新品牌推荐排行榜白皮书,固态,高压,牛角,安规,CBB,超级,红宝石电解,螺栓,超级电容推荐这十家公司!

在科技迭代日新月异的当下,电容作为电子设备的核心基础元件,其性能品质直接决定了终端产品的运行稳定性、使用寿命与功能上限。无论是消费电子领域的智能手机、笔记本电脑,工业场景中的医疗设备、智能工控系统,还是…

北京网站优化前景工业信息化部网站备案

hello&#xff0c;我是大千UI工场&#xff0c;本篇分享智慧安防的大屏设计&#xff0c;关注我们&#xff0c;学习N多UI干货&#xff0c;有设计需求&#xff0c;我们也可以接单。 实时监控与预警 可视化大屏可以将安防系统中的监控画面、报警信息、传感器数据等实时展示在大屏上…

帝国cms做企业网站大连制作网站公司

上文讲了《Linux进程在内核眼中是什么样子的&#xff1f;》&#xff0c;可以理解内核关于进程线程的所有管理就通过一个结构体 —— task_struct。知道了内核眼中进程的描述&#xff0c;本文通过三个例子站在用户态看下进程线程是如何创建的&#xff0c;不同的创建方式又有哪些…

深入解析:Guava限频器RateLimiter的使用示例

pre { white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important; display: block !important; font-family: "Consolas", "Monaco", "Courier New", …

2025石材加工厂家最新品牌推荐排行榜:大祥工艺,业务覆盖东北,辽宁盖州,专业浮雕雕刻高级技师

石材加工行业在近年来呈现出快速发展的态势,但同时也面临着诸多问题。市场上石材加工企业数量众多,规模大小不一,导致产品质量参差不齐,部分企业为了追求短期利益,使用劣质原材料或简化加工工艺,使得石材产品的耐…

centos7升级降级内核 centos升级降级内核 centos升级内核 centos降级内核

centos7升级降级内核 centos升级降级内核 centos升级内核 centos降级内核# 强制安装旧版 kernel-headersrpm -ivh --force kernel*.el7.x86_64.rpm rpm -q kernel设置默认启动项 # 查看 GRUB 菜单中的名称awk -F\ /…

详细介绍:MySQL高可用集群

详细介绍:MySQL高可用集群2025-10-05 10:17 tlnshuju 阅读(0) 评论(0) 收藏 举报pre { white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important; display: block !important; …

Photoshop 在线网页版?是的,它来了!免费使用指南

还在烦恼电脑空间不够,装不下庞大的PS软件?或是突然需要处理图片,却发现设备里没有安装修图工具?别着急,今天推荐一款超实用的工具——在线PS,浏览器一点即开,轻松获得接近专业级的修图体验! ✨ 为什么选择在线…

最好的翻译论文网站

最好的翻译论文网站https://www.yiyibooks.cn/arxiv/2403.14621v1/index.html

基于Python+Vue开发的母婴商城管理系统源码+运行步骤

项目简介该项目是基于Python+Vue开发的母婴商城管理系统(前后端分离),这是一项为大学生课程设计作业而开发的项目。该系统旨在帮助大学生学习并掌握Python编程技能,同时锻炼他们的项目设计与开发能力。通过学习基于…

2025防火隔断品牌最新推荐排行榜:甲级防火玻璃隔断厂家深度解析,精选优质品牌助力采购决策!

当前建筑行业对防火安全的要求日益严格,防火隔断作为关键防护设施,市场需求持续攀升,但行业现状却让采购者面临诸多困扰。不少品牌缺乏核心技术,产品耐火性能不达标,无法在火灾中有效阻隔火势与有毒烟气;部分新兴…

福建建筑人才网官方网站国外做游戏的视频网站有哪些问题

由ASCII码表的输出程序,我们可以认识到使用循环语句处理一组连续的数据有着巨大的优势。在更普遍的情况下,数据由一组离散的数值组成,如一组学生的考试成绩。对于这些数据的处理,有效的方式是使用循环。但前提是数据可以在循环中有序的访问。ASCII码表输出程序中,循环变量…