【本地缓存篇】如何实现本地缓存?

在这里插入图片描述

如何实现本地缓存?

  • ✔️典型解析
    • ✔️数据结构
    • ✔️线程安全
    • ✔️对象上限
    • ✔️清除策略
    • ✔️过期时间
  • ✔️扩展知识仓
    • 基于Caffeine实现本地缓存


✔️典型解析


所谓本地缓存,就是和应用服务器在一起的缓存工具,将需要缓存的数据放到本地缓存中,可以大大的提升访问速度。


在设计本地缓存时,一般需要考虑以下几个方面的问题:


✔️数据结构


一般来讲,为了提升缓存的效率,通常采用Key-Value结构进行数据存储,也就是说,缓存中的数据保存和读取都需要有一个Key,通过Key来读取固定的缓存的Value。

✔️线程安全


本地缓存一定要考虑线程安全的问题,因为大多数情况下本地缓存都是一个全局可访问的变量,那么就会有多个线程同时访问,所以线程安全问题不容忽视。


✔️对象上限


因为是本地缓存,而本地内存中的数据是要占用JVM的堆内存的,所以内存是有上限要求的,如果无限存储,最终一定会导致OOM的问题。


✔️清除策略


为了避免OOM的问题,一般会考虑在缓存中增加清除策略,通过一定的手段定期的清理掉一些数据,来保证内存占用不会过大,常见清除策略主要有有LRU(最近最少使用)、FIFO(先进先出)、LFU(最近最不常用)、SOFT(软用)、WEAK(弱用)等;


✔️过期时间


有了清除策略并不能保证百分百的可以删除数据,极端情况会会使得某些数据一直无法删除。这时候就需要有一种机制能够保证某些K-V一定可以删除。通常采用的方案是给每一个缓存的kev设置过期时间,当达到过期时间之后直接删除,采用清除策略+过期时间双重保证;


考虑到以上这些问题之后,就可以考虑如何具体实现一个本地缓存了。


最简单的方式是通过HashMap来实现一个本地缓存,因为他本身就是一种Key-Value结构的,并且如果使用ConcurrentHashMap的话,也能保证线程安全,不过需要自己实现对象上限、过期策略以及清除策略。


除此之外,也有一些比较成熟的开源的本地缓存框架可以直接使用,比较常用的有:


  • Guava Cache
  • Caffeine (推荐)
  • Encache

推荐优先使用Caffeine作为本地缓存,在功能上,GuavaCache支持的功能,Caffeine都支持,另外Caffeine支持异步Cache和写入外部资源,这两个Guava Cache是不支持的。Caffeine也是Spring 5中默认支持的Cache。而Caffeine在性能上要比GuavaCache好很多,主要有以下几个原因:


1 . 剔除算法,GuavaCache采用的是 [LRU] 算法,而Caffeine采用的是[Window TinyLFU] 算法,这是两者之间最大,也是根本的区别。


2 . 立即失效,Guava会把立即失效(例如: expireAfterAccess(0) and expireAfterWrite(0)) 转成设置最大Size为0。这就会导致剔除提醒的原因是SIZE而不是EXPIRED。Caffiene能正确识别这种剔除原因。


3 . 取代提醒,Guava只要数据被替换,不管什么原因,都会触发剔除监听器。而Cafiene在取代值和先前值的引用完全一样时不会触发监听器。


4 . 异步化,Caffiene的很多工作都是交给线程池去做的(默认: ForkJoinPool.commonPool()),例如: 剔除监听器,刷新机制,维护工作等


回顾博文: 【本地缓存篇】LFU、LRU 等缓存失效算法


✔️扩展知识仓


基于Caffeine实现本地缓存


import com.github .benmanes .caffeine.cache.Cache;
import com.github.benmanes .caffeine.cache.Caffeine;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.stereotype.Component;


import java.util.concurrent.TimeUnit;

/**
*    本地缓存工具
*     @author wwwwwwwwwwwwwwwwwwww
*/
@Component
public class LocalCacheManager implements InitializingBean {
	private Cache<String,String> localCache;

	/**
	*    向缓存中保存数据,如果已经存在则不覆盖
	*/
	public void putIfNotExist(String key,String value)  {
		if (localCache.getIfPresent(key) == null)  {
			localCache.put(key, value);
		}
	}

	/**
	*
	*     根据key获取缓存数据
	*     @param key
	*/
	public String get(String key)  {
		return localCache.getIfPresent(key);
	}

	public void del(string key) {
		localCache.invalidate(key);
	}

	/**
	*    在bean初始化时,初始化本地缓存
	*/
	@Override
	public void afterPropertiesSet() {
		localCache = Caffeine.newBuilder()
		.expireAfterWrite(10TimeUnit.SECONDS)
		.expireAfterAccess(10TimeUnit.SECONDS)
		.maximumsize(1000)
		.build();
		
	}

	
}

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

【轻松入门】OpenCV4.8 + QT5.x开发环境搭建

引言 大家好&#xff0c;今天给大家分享一下最新版本OpenCV4.8 QT5 如何一起配置&#xff0c;完成环境搭建的。 下载OpenCV4.8并解压缩 软件版本支持 CMake3.13 或者以上版本 https://cmake.org/ VS2017专业版或者以上版本 QT5.15.2 OpenCV4.8源码包 https://github.com/op…

常用的 linux 命令

常用的 linux 命令 1.从其他机器拷贝文件夹2.查看哪个程序在用特定端口3.实时监控日志文件内容4.查看指定用户拥有的进程5.查看磁盘空间使用情况6.文件搜索which&#xff08;whereis&#xff09; 显示系统命令所在目录find 查找任何文件或目录1&#xff09; 根据文件名称查找2)…

【Linux驱动】Linux中断(一)—— 设备树中断节点

裸机使用中断需要通过寄存器手动配置&#xff0c;但有了 Linux 系统后&#xff0c;Linux内核提供了完善的中断框架&#xff0c;我们只需要申请中断&#xff0c;然后注册中断服务函数即可。 一、设备树中断属性 既然驱动中要注册中断服务函数&#xff0c;我们首先需要知道三个点…

实战 | 使用OpenCV快速去除文档中的表格线条(步骤 + 源码)

导 读 本文主要介绍如何使用OpenCV快速去除文档中的表格线条,并给详细步骤和代码。 背景介绍 测试图如下,目标是去除下面三张图中的表格线条,方便后续图像处理。 实现步骤 下面演示详细步骤,以图1为例: 【1】获取二值图像:加载图像、转为灰度图、OTSU二值化 i…

记录 | ubuntu源码编译python3.7.3(指定版本)

一、安装依赖包 sudo apt-get install -y make build-essential libssl-dev zlib1g-dev sudo apt-get install -y libbz2-dev libreadline-dev libsqlite3-dev wget curl llvm sudo apt-get install -y libncurses5-dev libncursesw5-dev xz-utils tk-dev 二、从Python网…

mapboxgl 中给地图添加遮罩蒙版,并不遮罩其中一块区域

文章目录 概要效果预览技术思路技术细节小结 概要 本篇文章主要是给一整块地图添加遮罩层蒙版&#xff0c;但是不遮罩其中一个区域&#xff0c;以反向高亮地区内容。 效果预览 技术思路 这里要实现某个区域反显高亮&#xff0c;需要这个区域的边界json文件&#xff0c;与ech…

Flink1.17实战教程(第三篇:时间和窗口)

系列文章目录 Flink1.17实战教程&#xff08;第一篇&#xff1a;概念、部署、架构&#xff09; Flink1.17实战教程&#xff08;第二篇&#xff1a;DataStream API&#xff09; Flink1.17实战教程&#xff08;第三篇&#xff1a;时间和窗口&#xff09; Flink1.17实战教程&…

华锐三维云展平台创建VR文化宣传展厅,让文化传承变得更便捷和高效

随着科技的不断发展&#xff0c;虚拟现实&#xff08;VR&#xff09;技术已经逐渐走进人们的生活。通过华锐云展平台&#xff0c;可以通过拖、拉、拽&#xff0c;快速自由地创建一个VR文化宣传展厅&#xff0c;VR文化宣传展厅为人们提供了一个全新的、沉浸式的文化体验空间。在…

uniapp的分包使用记录

UniApp的分包是一种将应用代码划分为多个包的技术。分包的核心思想是将不同部分的代码划分为不同的包&#xff0c;按需加载&#xff0c;从而提高应用性能。使用UniApp的条件编译功能&#xff0c;开发人员可以根据需要将代码划分为多个包。每个包都包含一组页面和组件&#xff0…

在国内如何在Tiktok上买东西(在tiktok上付款)??

TikTok是一款由中国公司字节跳动&#xff08;ByteDance&#xff09;开发的社交媒体应用&#xff0c;于2016年9月正式上线。它在全球范围内迅速走红&#xff0c;特别受到年轻用户的喜爱。以下是关于TikTok的介绍以及其一些优势 支持的卡头有5561、531993 //点我办卡&#xff0c…

stm32H743编译器关于浮点类型强制转换传参的bug

局部函数&#xff0c;正常传参 当测试函数作为局部函数和main函数写在同一个文件中时&#xff0c;参数可以正常传递。函数参数和形参都为3.14 float value 0.0; void float_test(float _v) {value _v; }int main(void) {float_test(3.14f);while(1); } keil仿真截图&#…

关于MySQL、分布式系统、SpringCloud面试题

前言 之前为了准备面试&#xff0c;收集整理了一些面试题。 本篇文章更新时间2023年12月27日。 最新的内容可以看我的原文&#xff1a;https://www.yuque.com/wfzx/ninzck/cbf0cxkrr6s1kniv MySQL 索引 说一下有哪些锁&#xff1f; 行锁有哪些&#xff1f; 性能优化 分库分表…

Java生态系统的进化:从JDK 1.0到今天

目录 前言 JDK 1.0&#xff1a;开启Java时代 JDK 1.1&#xff1a;Swing和内部类 JDK 1.2&#xff1a;Collections框架和JIT编译器 JDK 1.5&#xff1a;引入泛型和枚举 JDK 1.8&#xff1a;Lambda表达式和流 JDK 11以后&#xff1a;模块化和新特性 未来展望 总结 作者简…

3D换肤在服装行业的应用

在线工具推荐&#xff1a; 3D数字孪生场景编辑器 - GLTF/GLB材质纹理编辑器 - 3D模型在线转换 - Three.js AI自动纹理开发包 - YOLO 虚幻合成数据生成器 - 三维模型预览图生成器 - 3D模型语义搜索引擎 通过采用高质量的 3D 模型&#xff0c;企业可以提供更加身临其境的体…

cpp_07_类型转换构造_析构函数_深拷贝_静态成员

1 类型转换构造函数 1.1 why? 基本类型之间的转换&#xff0c;编译器内置转换规则&#xff1a;int -> double 类类型之间的转换&#xff0c;编译器不知道转换规则&#xff0c;需要用户提供&#xff1a;Cat -> Dog // consconv_why.cpp 为什么需要自定义转换 #includ…

ARM CCA机密计算软件架构之RMI领域管理接口与RSI领域服务接口

领域管理接口 领域管理接口&#xff08;RMI&#xff09;是RMM与正常世界主机之间的接口。 RMI允许正常世界虚拟机监视器向RMM发出指令&#xff0c;以管理领域。 RMI使用来自主机虚拟机监视器的SMC调用&#xff0c;请求RMM的管理控制。 RMI使得对领域管理的控制成为可能&…

STM32 基础知识(探索者开发板)--93讲 PWM

预分频器相当于一个计数器&#xff0c;2分频就是接收2个脉冲传递一个脉冲&#xff0c;3分频就是接收3个脉冲传递一个脉冲&#xff0c;最高65535分频&#xff0c;那么总计时间能达到65535*65535*1/72MHZ 约59秒&#xff0c;没有分频器只能计数最高0.09秒 PWM配置步骤 1.配置定时…

Vue : Object.defineProperty()

给对象添加属性: <script>let person {name : 张三,sex : 男}Object.defineProperty(person,age,{value : 18})console.log(person)</script> 控制台查看: 但是添加的属性是不能被遍历的: 但是如果你想又使用defineProperty添加属性, 又想遍历, 那么就在这个def…

阿里云oss拷贝(包含移动的代码)文件并返回下载地址

oss拷贝文件官方地址&#xff1a; https://help.aliyun.com/zh/oss/developer-reference/java-copy-objects?spma2c4g.11186623.0.0.16f76083xr3lKM 步骤1&#xff1a;oss的Maven依赖 <!-- OSS --><dependency><groupId>com.aliyun.oss</groupId>&l…

GIT如何重新生成ssh密钥过程

GIT如何重新生成ssh密钥过程 一、生成密钥前需要把之前的密钥删除吆 第一步&#xff1a;重新配置用户名和邮箱&#xff08; Git Bash 或命令窗口&#xff09; 1、配置用户命令&#xff1a;git config --global user.name “xxxxx” 2、配置邮箱命令&#xff1a;git config …