cache之guava
本文主要记录guava_cache的学习心得!
缓存是什么?为何要用缓存呢?
先参考下图!

这是一张小白图!简单形容了一个普普通通的服务端请求的处理模型! 当一个request请求通过网络不远千里的来到我们的机房! 首先nginx会给它找到一个合适的处理窗口,也就是我们的jvm进程,当jvm在进程空间内没有找到请求的结果,会尝试去分布式缓存中获取!如果分布式缓存中任然没有命中,再尝试去数据库中获取!
在上图中,a,b,c,d耗时逐渐增加,而且是跳跃式的增加!DB作为稳定性,安全性最值得依赖的存储空间,作为保障放在了最后一关!请求到数据库,需要通过漫长的网络和大量的磁盘io才能找到正确的数据!而又因为磁盘的io速度远远小于内存io,所以出现了分布式缓存!可是访问分布式缓存又隔着一层网络io,于是进程内部缓存应运而生!
以上三种角色,没有优劣之分,都在我们的系统中,承担了不可替代的重要角色!
讲到这里可以粗糙的理解为:缓存就是我们进程空间内部一片存储空间,是为了数据可以被进程更快速访问!
这里很多人会疑问,那实例个HashMap不就可以实现吗? 干嘛要提guava-cache!
这里就要说一下,机器的内存资源是十分宝贵的,内存相比磁盘的特点就是小而快!如果随便定义一块进程内的存储空间当cache,当原来越多的数据被放入,内存就又了爆掉的风险!而为这块进程内部存储空间包上了一层管理手段,使进程更合理更安全高效的使用内存,就是我们的缓存技术!为了更高效安全的使用内存,诸多缓存技术被开发出来,guava cache就是其中之一!
下面会从代码,去学习guava cache的使用和实现!
1 构建 (使用lodingcache作为示例)

guava cache的构建使用了简单易懂的构建者模式!核心参数如图:
maximumSize 最大存储数量,防止内存被过度使用而爆掉
expireAfterAccess 最后获取后的过期时间,无效数据剔除!
expireAfterWrite 写入后的过期时间,防止数据累积过多!同 expireAfterAccess 可二选一!
removalListener 数据移除时的监听器!
CacheLoader 数据加载器! 核心方法load(key), 在内存中没有获取到数据时会调用,将数据加载到cache中!
maximumSize ,expireAfterAccess ,expireAfterWrite 保证了内存空间使用的安全合理!
removalListener 和 CacheLoader 则提供了多样化的cache使用方式!
2 get方法 (核心方法)
可见,loadingCache的实现是LocalCache的静态内部类LocalLoadingCache,调用getOrLoad(key)来获取value!getOrLoad内部调用get(key,loader)方法!

在get方法内部,可以看到,guava cache使借鉴了jdk 1.8版本之前的ConcurrentHashMap,使用segment分段的方式,保证在多线程情景下的高效安全访问!

上图的get方法实现中可以看到!首先会判断 缓存中元素数量!
如果缓存中有数据,count!=0,通过key和hash获取value,可见getEntry() -->getFirst(hash) ,其结构同jdk HashMap原理,使用 AtomicReferenceArray 作为table数组,根据hash定位下表,获取到目标链表,然后遍历链表,比对key值,尝试获取value!
如果获取到value,会使用recordRead方法记录当前时间戳为最后获取此key的时间,读取此key的次数+1!在返回value时,会调用 scheduleRefresh()刷新任务方法返回!这里也可以看到cache包装的强大功能,根据当前时间now减value的写入时间戳的结果是否大于刷新时间间隔,来判断是否需要刷新!

是,则使用loader加载器加载新值,刷新缓存并返回!否,则旧值返回!
如果缓存中没有数据,count==0 ,也会执行 lockedGetOrLoad()方法!如下:

依然是根据hash,定位到index下标,如果找到下标,则循环遍历链表,比对key值,获取value!其中,会判断获取到的value,如果是null,塞入队列,等待异步清除!
如果不是null,也要判断是否过期,在过期的情况下,依然会塞入异步清除队列!
如果没有获取到value的情况下,判断是否需要创建新的entry,既createNewEntry==true,会创建一个弱引用或软引用,LocalCache.LoadingValueReference(),放进table中,最后调用load()方法,为该引用加载数据!
注:判断数据是否过期的方法isExpired()

如果设置的是写入后过期,则拿当前时间减写入时间和过期时间比较大小,
如果是最后一次获取后过期,则拿当前时间减最后一次access时间 和过期时间比较大小!
其上为cache的核心方法get()的大概实现!
总价概括为:cache使用了segment分段锁控制了并发写入,使用了数组+hash+链表的数据结构实现了高效读写,数组是juc大神dog.lea写的原子性安全读写的AtomicReferenceArray,使用了引用队列存放key,value,保证了gc回收及时!recencyQueue 和 accessQueue (前者是读取是写入,后者是加锁状态下的写都会写入)保证了回收算法的异步高效实现!
由此可见,内存的使用,在服务端是一件严谨甚至严苛的事,使用得当,会给服务的效率带来极大的提升!使用不得当,内存的安全,进程的生命,就会立即受到致命的威胁!
本地缓存技术,越来越被重视。以下为几种常见cache技术的特性:
1 ehcache,使用简单,访问效率高,轻量接入, 适合数据更新少,并发低的场景下
2 guava cache 功能强大,配置多,支持三种淘汰策略,支持刷新,移除,记数等功能,支持弱引用 软引用, 适合有一定的内存空间的条件,频繁读写场景下!
3 jetcache 阿里开源,springboot支持,亲redis,多级缓存使用良好!
4 caffeine是guava的升级款,也是最近被主推的cache!使用方式同guava区别不大,但是性能上提升很大!
cache之guava的更多相关文章
- [Java 缓存] Java Cache之 Guava Cache的简单应用.
前言 今天第一次使用MarkDown的形式发博客. 准备记录一下自己对Guava Cache的认识及项目中的实际使用经验. 一: 什么是Guava Guava工程包含了若干被Google的 Java项 ...
- Spring cache简单使用guava cache
Spring cache简单使用 前言 spring有一套和各种缓存的集成方式.类似于sl4j,你可以选择log框架实现,也一样可以实现缓存实现,比如ehcache,guava cache. [TOC ...
- Ehcache与Guava Cache的区别浅谈
最近在做一些缓存改造的场景,有如下一些经验总结: 缓存版本: Ehcache:2.8.3 Guava:17.0 Ehcache支持持久化到本地磁盘,Guava不可以: Ehcache有现成的集群解决方 ...
- (翻译)Google Guava Cache
翻译自Google Guava Cache This Post is a continuation of my series on Google Guava, this time covering G ...
- SpringBoot学习笔记(6) SpringBoot数据缓存Cache [Guava和Redis实现]
https://blog.csdn.net/a67474506/article/details/52608855 Spring定义了org.springframework.cache.CacheMan ...
- Spring Boot 揭秘与实战(二) 数据缓存篇 - Guava Cache
文章目录 1. Guava Cache 集成 2. 个性化配置 3. 源代码 本文,讲解 Spring Boot 如何集成 Guava Cache,实现缓存. 在阅读「Spring Boot 揭秘与实 ...
- spring boot guava cache 缓存学习
http://blog.csdn.net/hy245120020/article/details/78065676 ****************************************** ...
- Spring配置cache(concurrentHashMap,guava cache、redis实现)附源码
在应用程序中,数据一般是存在数据库中(磁盘介质),对于某些被频繁访问的数据,如果每次都访问数据库,不仅涉及到网络io,还受到数据库查询的影响:而目前通常会将频繁使用,并且不经常改变的数据放入缓存中,从 ...
- Guava学习
Guava学习笔记目录 Guava 是一个 Google 的基于java1.6的类库集合的扩展项目,包括 collections, caching, primitives support, concu ...
随机推荐
- Linux服务之DHCP服务篇(scp)
一.概念 名称:DHCP----Dynamic Host Configuration Protocol 动态主机配置协议 功能:DHCP是一个局域网的网络协议,使用UDP协议工作 主要用途:给内部网络 ...
- teprunner测试平台定时任务这次终于稳了
teprunner测试平台已经有一个多月没有更新了,主要原因是定时任务不够稳定,经过反复试错,找到了解决办法,这次终于稳定了. 本文开发内容 作为测试平台而言,定时任务算是必备要素了,只有跑起来的自动 ...
- 如何屏蔽 iOS 软件自动更新,去除更新通知和标记
适用于 iOS.iPadOS 和 watchOS,即 iPhone.iPad 和 Apple Watch 通用. 请访问原文链接:https://sysin.org/article/Disable-i ...
- CoSky-Mirror 就像一个镜子放在 Nacos、CoSky 中间,构建一个统一的服务发现平台
CoSky 基于 Redis 的服务治理平台(服务注册/发现 & 配置中心) Consul + Sky = CoSky CoSky 是一个轻量级.低成本的服务注册.服务发现. 配置服务 SDK ...
- django2中namespace和name的使用
django2中namespace和name的使用 一.在Django <= 1.11 我们通过关键词namespace参数定义名称空间 1.projects/urls.py from ...
- TensorFlow分布式(多GPU和多服务器)详解
本文介绍有关 TensorFlow 分布式的两个实际用例,分别是数据并行(将数据分布到多个 GPU 上)和多服务器分配. 玩转分布式TensorFlow:多个GPU和一个CPU展示一个数据并行的例子, ...
- cuDNN 功能模块解析
Abstract 本cuDNN 8.0.4开发人员指南概述了cuDNN功能,如可自定义的数据布局.支持灵活的dimension ordering,striding,4D张量的子区域,这些张量用作其所有 ...
- 认真总结Vue3中ref与reactive区别和isRef与isReactive 类型判断
1.什么是ref? 1.ref和reactive-样 也是用来实现响应式数据的方法 由于reactive必须传递一个对象, 所以导致在企业开发中如果我们只想让某个变量实现响应式的时候会非常麻烦 所以V ...
- 深入理解java虚拟机笔记Chapter3-内存分配策略
内存分配策略 新生代和老年代的 GC 操作 新生代 GC 操作:Minor GC 发生的非常频繁,速度较块. 老年代 GC 操作:Full GC / Major GC 经常伴随着至少一次的 Minor ...
- Django(68)drf分页器的使用
前言 当后台返回的数据过多时,我们就要配置分页器,比如一页最多只能展示10条等等,drf中默认配置了3个分页面 PageNumberPagination:基础分页器,性能略差 LimitOffsetP ...
