guava cache 缓存回收及原理实现

 

一、简介

Guava cache 是一个全内存本地缓存。它拥有并发策略、缓存过期机制、缓存移除机制、缓存统计等功能.

缓存的优势:

1、减少网络传输的开销

2、减少数据序列化和反序列化

3、加快了访问速度(与数据库、文件系统相比)。

缓存的使用场景:

1、缓存全量数据

2、缓存热点数据

二、基本用法

1、缓存加载

这两种方法都实现一种逻辑:从缓存中取key的值,如果该key已经缓存过,直接返回缓存中的值,

如果没有缓存该key,可以通过某个方法来获取这个值。

  • CacheLoader

  • Callable

2、策略分析

  • expireAfterAccess 读写缓存后多久过期

  • expireAfterWrite 写缓存后多久过期

    并发时的特性:(无论缓存中是否存在数据)如果当其他线程在加载数据,当前线程会一直阻塞等待其它线程加载完成数据

     

缺点:导致缓存穿透

  • refreshAfterWrite 写缓存后多久刷新数据,只阻塞加载数据线程,其他线程返回旧值

    并发时的特性:

    a、缓存中没有数据时(初始化缓存数据时),如果其它线程在加载数据的时候,当前线程会一直阻塞等待其它线程加载数据完成。

    b、缓存中有数据(已经初始化缓存中的数据时),如果当前线程正在加载数据,其它线程返回旧数据。

     

缺点:导致数据过旧的问题

3、缓存回收

  • 基于容量回收

    CacheBuilder.maxmumSize(long)

  • 基于时间回收

    CacheBuilder.expireAfterAccess()

    CacheBuilder.expireAfterWrite()

  • 基于引用回收

    软引用和弱引用

    CacheBuilder.weakKeys()

    当键没有其它(强或软)引用时,缓存项可以被垃圾回收。因为垃圾回收仅依赖恒等式(==),使用弱引用键的缓存用==而不是equals比较键。

    CacheBuilder.weakValues()

    CacheBuilder.softValues()

    软引用只有在响应内存需要时,才按照全局最近最少使用的顺序回收。使用软引用时需要考虑性能影响。使用软引用值的缓存同样用==而不是equals比较值。

引用类型

描述

回收时间

用途

备注

强引用

程序中随处可见

永不回收

普通对象引用

 

软引用

描述对象有用但不是必须的

内存不足回收

缓存对象

软引用可以和一个引用队列(ReferenceQueue)联合使用,如果软引用所引用的对象被垃圾回收器回收,java虚拟机就会把这个软引用加入到与之关联的引用队列中

弱引用

描述对象不是非必须的

jvm垃圾回收

缓存对象

 

 

4、其它

三、缓存回收原理及实现

1、什么是LRU算法

LRU(Least recently used,最近最少使用)是核心思想是基于“如果数据最近被访问过,那将来被访问的几率也更高”。

1.1:新数据插入到链表的头部。

1.2:每当缓存命中(即缓存数据被访问),则将数据移到链表头部。

1.3: 当链表满的时候,将链表尾部的数据丢弃。

 

2、LocalCache数据结构

 

名称

类型

作用

segments

Segment<k,V>[]

实现ReentrantLock锁,减少锁的粒度,提高并发度。好处:分段锁很好保证并发读写的效率,因此支持非阻塞的读和不同段之间的并发写

table

AtomicReferenceArray<ReferenceEntry<K,V>

存放键值对的地方

referenceEntry

ReferenceEntry<K,V>

封装键值对

keyReferenceQueue

ReferenceQueue<K>

已经被GC,需要内部清理key引用队列

valueReferenceQueue

ReferenceQueue<V>

已经被GC,需要内部清理value引用队列

recencyQueue

Queue<ReferenceEntry<K,V>>

记录当entries被访问时,去更新accessQueue中顺序。在segment中当segment上限值或是写操作发生会去更新accessQueue顺序,同时清空recencyQueue。

writeQueue

Queue<ReferenceEntry<K,V>>

按照写入时间进行排序的元素队列,写入元素时会把它加入队列的队尾

accessQueue

Queue<ReferenceEntry<K,V>>

按照访问时间进行排序的元素队列,访问或是写入元素时会把它加入到队列的队尾。

3、segment如何清理(evict) entry

evict方式

使用cacheBuilder构建的缓存不会“自动”执行清理和回收工作,也不会在某个缓存项过期后马上清理。

相反,它会在写操作时顺带做少量的维护工作,或者偶尔在读操作时做——如果写操作实在太少的话。

理由:如果guava使用开启一个后台线程每隔一段时间来扫描一次table以evict哪些已经expire的entry,

这样的增加资源的消耗。

evict对象

基于引用回收

keyReferenceQueue

valueReferenceQueue

基于时间回收

writeQueue

accessQueue

 

evict流程

基于引用和时间回收策略

put开始时

 

get结束之前

 

基于容量回收策略(LRU)

put结束之前

前提条件:在设置maxmumSize或maximumWeight时,才会进行该操作。

weight的作用

1. 对weight值为0时,在计算因为size limit而evict是忽略该Entry(它可以通过其他机制evict)。

2. 如果设置了maximumWeight值,则当Cache中weight和超过了该值时,就会引起evict操作。

 

四、总结

设计缓存系统中过期机制时,可以考虑在读和写操作进行清理操作,从而提供效率。

 

参考文档:

【1】、google guava cache缓存基本使用讲解

【2】、[Google Guava] 3-缓存

【3】、CachesExplained

【4】、自定义LRU算法的缓存实现

【5】、Google Guava Cache 全解析

【6】、Java Cache系列之Guava Cache实现详解

【7】、GuavaCache

【8】、Guava cache 机制及源码分析

【9】、Java的引用类型

【10】、Guava Cache 的缓存管理与使用

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值