文章目录

  • 使用场景
  • Guava Cache 的优势
  • Guava Cache使用
    • CacheLoader
    • Callable
    • 删除
      • 主动删除
      • 过期删除
      • 基于容量删除
      • 引用删除
    • 高级用法
    • 并发设置
    • 更新锁定
    • GuavaCache高级实战之疑难问题
      • GuavaCache会oom(内存溢出)吗
      • GuavaCache缓存到期就会立即清除吗
      • GuavaCache如何找出最久未使用的数据

使用场景

随着互联网用户越来越多,并发量、吞吐量越来越大

本地缓存的应用场景:

  1. 对性能有非常高的要求
  2. 不经常变化
  3. 占用内存不大
  4. 有访问整个集合的需求
  5. 数据允许不时时一致
    例如:拉勾网首页,由于首页经常被访问,可以将职位信息:java开发、大数据开发等放在本地缓存中。

guava cache:高并发,不需要持久化
currentHashMap:高并发
Ehcached:持久化 二级缓存

Guava Cache 的优势

缓存机制淘汰算法可参考博文:本地缓存之LRU FIFO实现

  1. 缓存过期和淘汰机制:LRU
  2. 并发处理能力:类似CurrentHashMap,是线程安全的,采用了分段锁机制,将一个集合分成若干个人partiton ,每个Patrtiton一把锁,master多分区,利用segement作分区
  3. 更新锁定:GuavaCache可以在CacheLoader的load方法中加以控制,对同一个key,只让一个请求去读源并回填缓存,其他请求阻塞等待。.
  4. 集成数据源:而GuavaCache的get可以集成数据源,在从缓存中读取不到时可以从数据源中读取数据并回填缓
  5. 监控缓存加载/命中情况

Guava Cache使用

Cache创建:

方法 作用
maximumSize 容量
expireAfterWrite 缓存项在给定时间内没有被写访问(创建或覆盖),则回收
recordStats 缓存项在给定时间内没有被读/写访问,则回收
removalListener 移除监听器
weakKeys 弱引用存储键,当键没有其它(强或软)引用时,缓存项可以被垃圾回收
weakValues 使用弱引用存储值。当值没有其它(强或软)引用时,缓存项可以被垃圾回收
concurrencyLevel 并发操作

CacheLoader、Callable功能相同,都是在调用get方法时候,如果缓存不存在则指定数据源加载

CacheLoader

在创建缓存对象初始化时使用

模拟数据源

    public static HashMap<Integer, Integer> sourceMap = new HashMap<>();static {for (int i = 0; i < 10; i++){sourceMap.put(i, i);}}

使用demo

    public static void main(String[] args) throws ExecutionException {LoadingCache<Object, Object> cache = CacheBuilder.newBuilder().maximumSize(5).build(new CacheLoader<Object, Object>() {@Overridepublic Object load(Object o) throws Exception {return sourceMap.get(o);}});for (int i = 0; i < 10; i++){cache.get(i);}System.out.println(cache.size());System.out.println(cache.asMap());}

Callable

调用get方法时当缓存数据不存在时候从数据源加载数据

使用demo:

    @Testpublic void call() throws ExecutionException {Cache<Object, Object> cache = CacheBuilder.newBuilder().maximumSize(5).build();Object value = cache.get(1, new Callable<Integer>() {@Overridepublic Integer call() throws Exception {return sourceMap.get(1);}});System.out.println(value);}

删除

主动删除

    @Testpublic void doDel() throws ExecutionException {LoadingCache<Object, Object> cache = CacheBuilder.newBuilder().maximumSize(5).expireAfterAccess(3, TimeUnit.SECONDS).build(new CacheLoader<Object, Object>() {@Overridepublic Object load(Object o) throws Exception {return sourceMap.get(o);}});initCache(cache);//主动删除 key为1cache.invalidate(1);System.out.println("主动删除");displayCache(cache);// 批量删除cache.invalidateAll(Arrays.asList(1,2));System.out.println("批量删除");displayCache(cache);}

过期删除

expireAfterAccess:如果在一定时间内没被访问则数据过期

    @Testpublic void expireTimeDel() throws ExecutionException, InterruptedException {LoadingCache<Object, Object> cache = CacheBuilder.newBuilder().maximumSize(5).expireAfterAccess(3, TimeUnit.SECONDS).build(new CacheLoader<Object, Object>() {@Overridepublic Object load(Object o) throws Exception {return sourceMap.get(o);}});initCache(cache);Thread.sleep(1000);cache.getIfPresent(1);Thread.sleep(2000);displayCache(cache);}

基于容量删除

    @Testpublic void sizeDel() throws ExecutionException {LoadingCache<Object, Object> cache = CacheBuilder.newBuilder().maximumSize(1).build(new CacheLoader<Object, Object>() {@Overridepublic Object load(Object o) throws Exception {return sourceMap.get(o);}});Object v = cache.get(1);System.out.println(v);//自动删除1Object v2 = cache.get(2);displayCache(cache);}

引用删除

开启weakValues功能,采用弱引用,对引用不了解的可以看看,我的文章

    @Testpublic void referenceDel(){Cache<Object, Object> cache = CacheBuilder.newBuilder().maximumSize(3).weakValues().build();cache.put("1",new Object());//强制垃圾回收System.gc();System.out.println(cache.getIfPresent("1"));}

高级用法

并发设置

设置 concurrencyLevel 使得缓存支持并发的写入和读取

Cache<Object, Object> cache = CacheBuilder.newBuilder().maximumSize(3).concurrencyLevel(Runtime.getRuntime().availableProcessors()).build();

更新锁定

GuavaCache提供了一个refreshAfterWrite定时刷新数据的配置项,如果经过一定时间没有更新或覆盖,则会在下一次获取该值的时候,会在后台异步去刷新缓存

刷新时只有一个请求回源取数据,其他请求会阻塞(block)在一个固定时间段,如果在该时间段内没有获得新值则返回旧值。

    @Testpublic void refresh() throws InterruptedException, ExecutionException {LoadingCache<Integer, Integer> cache = CacheBuilder.newBuilder().maximumSize(3).concurrencyLevel(Runtime.getRuntime().availableProcessors()).refreshAfterWrite(3, TimeUnit.SECONDS).build(new CacheLoader<Integer, Integer>() {@Overridepublic Integer load(Integer key) throws Exception {return sourceMap.get(key);}});cache.get(1);System.out.println("第一次取值: " + cache.getIfPresent(1));sourceMap.put(1, 10);Thread.sleep(5000);System.out.println("第二次取值: " + cache.getIfPresent(1));}

应用场景:accesstoken token失效 从公网拿token 采用更新锁定

GuavaCache高级实战之疑难问题

GuavaCache会oom(内存溢出)吗

会,当我们设置缓存永不过期(或者很长),缓存的对象不限个数(或者很大)时,比如:

Cache<String, String> cache = CacheBuilder.newBuilder()
.expireAfterWrite(100000, TimeUnit.SECONDS)
.build();

解决方案:缓存时间设置相对小些,使用弱引用方式存储对象

GuavaCache缓存到期就会立即清除吗

不是的,GuavaCache是在每次进行缓存操作的时候,如get()或者put()的时候,判断缓存是否过期。

一个如果一个对象放入缓存以后,不在有任何缓存操作(包括对缓存其他key的操作),那么该缓存不
会主动过期的。

GuavaCache如何找出最久未使用的数据

用accessQueue,这个队列是按照LRU的顺序放的缓存对象(ReferenceEntry)的,会把访问过的对象放在队列的最后。

并且可以很方便的更新和删除链表中的节点,因为每次访问的时候都可能需要更新链表,放入到链表的尾部。

这样,每次从access中拿出的头结点就是最久未使用的。

对应的writeQueue用来保存最久未更新的缓存队列,实现方式和accessQueue一样。

其他比较好的文章推荐:

中文教程

Guava总结好的博客

本地缓存之Guava简单使用相关推荐

  1. 重新认识下JVM级别的本地缓存框架Guava Cache——优秀从何而来

    Guava Cache初识 Guava是Google提供的一套JAVA的工具包,而Guava Cache则是该工具包中提供的一套完善的JVM级别的高并发缓存框架.其实现机制类似ConcurrentHa ...

  2. java本地缓存 google guava

    本地缓存产生背景: 本地缓存是指在我们本地的物理空间开辟出一片物理空间,专门用来存储我们需要向服务器端频繁需要的数据, 比如前端页面需要频繁的向后台访问某些数据,这时候我们每次都去数据库查找数据再返回 ...

  3. GUAVA本地缓存01_概述、优缺点、创建方式、回收机制、监听器、统计、异步锁定

    文章目录 ①. 本地缓存 - 背景 ②. 本地缓存 - 优缺点 ③. Guava Cache介绍 ④. Guava - 三种创建方式 ⑤. Guava - 如何回收缓存 ⑥. Guava - 移除监听 ...

  4. Spring Boot 集成 本地缓存Guava框架

    Spring Boot 作为主流微服务框架,拥有成熟的社区生态.市场应用广泛,为了方便大家,整理了一个基于spring boot的常用中间件快速集成入门系列手册,涉及RPC.缓存.消息队列.分库分表. ...

  5. java 自动过期缓存_Java自动过期本地缓存简单实现

    实际项目中常常需要用到本地缓存,特别是一些固定不变的数据,不想频繁调接口,因为http请求本身需要耗时,下面几个类对本地缓存作了简单实现,支持自动过期功能 LocalCache.javainterfa ...

  6. 高并发技巧-redis和本地缓存使用技巧

    在这篇文章中,我主要介绍的是分布式缓存和本地缓存的使用技巧,包括缓存种类介绍,各种的使用场景,以及如何使用,最后再给出实战案例. 众所周知,缓存最主要的目的就是加速访问,缓解数据库压力.最常用的缓存就 ...

  7. Redis与本地缓存组合食用,味道更佳!

    点击下方"IT牧场",选择"设为星标" 来源:juejin.cn/post/7000263632151904293 前言 设计示例 Redis结合本地缓存 后记 ...

  8. 构建本地缓存java_Java8简单的本地缓存实现

    这里我将会给大家演示用ConcurrentHashMap类和lambda表达式实现一个本地缓存.因为Map有一个新的方法,在key为Null的时候自动计算一个新的value值.非常适合实现cache. ...

  9. guava_使用Google Guava Cache进行本地缓存

    guava 很多时候,我们将不得不从数据库或另一个Web服务获取数据或从文件系统加载数据. 在涉及网络呼叫的情况下,将存在固有的网络延迟,网络带宽限制. 解决此问题的方法之一是在应用程序本地拥有一个缓 ...

最新文章

  1. C++输入输出流进制转换
  2. 详解KMP算法原理,以及完整java与C++实现
  3. codeforces280 C. Game on Tree(期望)
  4. android Module之间数据传递
  5. linux为已有磁盘扩容 kvm,KVM虚拟磁盘扩容
  6. mysql 修改root 密码
  7. pytorch从dataframe中提取信息,变为可训练的tensor
  8. 产品经理处理问题“五步法”模板
  9. flowable 中的互斥网关、并行网关、兼容网关、事件网关
  10. WPS2000的目录提取(转)
  11. react中dispatch_react-redux中连续两次dispatch-actions有顺序吗?
  12. 2020南京市(徐庄)高层次创业人才引进计划开启申报
  13. 24基础指标、macd指标详解、macd指标分析
  14. Ice Lake CPU RESET流程
  15. android组合按键截屏,三星安卓手机截图组合键图文汇总(4种)
  16. oracle expdp 11,oracle11g使用expdp/impdp备份数据
  17. 《零基础D编程入门》
  18. ZStack——存储模型:主存储和备份存储
  19. asp easp 开源框架_国内ASP开源建站系统一览
  20. ERROR: cannot launch node of type [map_server/map_server]: map_server等

热门文章

  1. mapper注入失败,NoSuchBeanDefinitionException: No qualifying bean of type [com.xxx.XxxMapper] found for d
  2. 列举python中可变数据类型_python 可变数据类型 和 不可变数据类型
  3. php ajax 加载列表,Ajax点击不断加载数据列表(图文教程)
  4. Java技术学习笔记:C/S 与B/S 区别
  5. 哪种语言 连接 oracle,Go语言连接Oracle(就我这个最全)
  6. 泊松分布的分布函数_《可靠性设计》——常用的概率分布
  7. 典型相关分析_2020-2025年中国海水淡化行业发展前景与投资预测分析报告
  8. python中用于标识字符串的定界符_001.python-基础-Template的字符串格式化
  9. linux nginx postgresql php,常用Web环境架设手册PNP:Postgresql+Nginx+PHP
  10. 计算机网络 --- 网络层路由算法与路由协议