本文主要记录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的更多相关文章

  1. [Java 缓存] Java Cache之 Guava Cache的简单应用.

    前言 今天第一次使用MarkDown的形式发博客. 准备记录一下自己对Guava Cache的认识及项目中的实际使用经验. 一: 什么是Guava Guava工程包含了若干被Google的 Java项 ...

  2. Spring cache简单使用guava cache

    Spring cache简单使用 前言 spring有一套和各种缓存的集成方式.类似于sl4j,你可以选择log框架实现,也一样可以实现缓存实现,比如ehcache,guava cache. [TOC ...

  3. Ehcache与Guava Cache的区别浅谈

    最近在做一些缓存改造的场景,有如下一些经验总结: 缓存版本: Ehcache:2.8.3 Guava:17.0 Ehcache支持持久化到本地磁盘,Guava不可以: Ehcache有现成的集群解决方 ...

  4. (翻译)Google Guava Cache

    翻译自Google Guava Cache This Post is a continuation of my series on Google Guava, this time covering G ...

  5. SpringBoot学习笔记(6) SpringBoot数据缓存Cache [Guava和Redis实现]

    https://blog.csdn.net/a67474506/article/details/52608855 Spring定义了org.springframework.cache.CacheMan ...

  6. Spring Boot 揭秘与实战(二) 数据缓存篇 - Guava Cache

    文章目录 1. Guava Cache 集成 2. 个性化配置 3. 源代码 本文,讲解 Spring Boot 如何集成 Guava Cache,实现缓存. 在阅读「Spring Boot 揭秘与实 ...

  7. spring boot guava cache 缓存学习

    http://blog.csdn.net/hy245120020/article/details/78065676 ****************************************** ...

  8. Spring配置cache(concurrentHashMap,guava cache、redis实现)附源码

    在应用程序中,数据一般是存在数据库中(磁盘介质),对于某些被频繁访问的数据,如果每次都访问数据库,不仅涉及到网络io,还受到数据库查询的影响:而目前通常会将频繁使用,并且不经常改变的数据放入缓存中,从 ...

  9. Guava学习

    Guava学习笔记目录 Guava 是一个 Google 的基于java1.6的类库集合的扩展项目,包括 collections, caching, primitives support, concu ...

随机推荐

  1. Linux如何查看文件的创建、修改时间?

    Linux如何查看文件的创建.修改时间? 利用stat指令查看文件信息 三种时间的介绍 ATime --文件的最近访问时间 只要读取时间,ATime就会更新 MTime --文件的内容最近修改的时间 ...

  2. Mysql 数据库基本操作

    1.数据库设置密码 [root@db02 scripts]# mysqladmin -uroot password 123 2.使用密码登录 #1.正确的方式(不规范) [root@db02 scri ...

  3. 2.5if语句

    判断(if)语句 目标 开发中的应用场景 if 语句体验 if 语句进阶 综合应用 01. 开发中的应用场景 生活中的判断几乎是无所不在的,我们每天都在做各种各样的选择,如果这样?如果那样?-- 程序 ...

  4. python3 使用random函数批量产生注册邮箱

    '''你是一个高级测试工程师,现在要做性能测试,需要你写一个函数,批量生成一些注册使用的账号. 1.产生的账号是以@163.com结尾,长度由用户输,产生多少条也由用户输入,2.用户名不能重复,用户名 ...

  5. DLL重定向处理

    说明 目前正在做的项目批次功能涉及第三方插件,而第三方插件需依赖4.* 版本的Newtonsoft.Json.dll,由于现有功能已经使用6.*版本的Newtonsoft.Json.dll,故采用了d ...

  6. 在Linux服务器,搭建K8s服务【脚本篇】

    前言 好久没有写博客了,本文主要是对网上文章的总结篇,主要是将安装和运行代码做了一次真机实验,亲测可用.文章内包含的脚本和代码,多来自于网络,也有我自己的调整和配置,文章末尾对参考的文献做了列举,方便 ...

  7. Psexec和wmiexec的原理和区别

    PSEXEC 针对远程建立连接的方式有两种,一种先建立IPC通道连接,然后直接使用,操作如下: net use \\192.168.0.1\ipc$ "password" /use ...

  8. java中的Class.forName的作用

    Class.forName有什么作用 Class.forName(xxx.xx.xx) 返回的是一个类 首先你要明白在java里面任何class都要装载在虚拟机上才能运行.这句话就是装载类用的(和ne ...

  9. TensorRT原理图示

    TensorRT原理图示 NVIDIA的核心 TensorRT是有助于在NVIDIA图形处理单元(GPU)的高性能推理一个C ++库.它旨在与TensorFlow,Caffe,PyTorch,MXNe ...

  10. JavaScript 中精度问题以及解决方案

    JavaScript 中的数字按照 IEEE 754 的标准,使用 64 位双精度浮点型来表示.其中符号位 S,指数位 E,尾数位M分别占了 1,11,52 位,并且在 ES5 规范 中指出了指数位E ...