Guava Cache原理

Guava Cache原理

GuavaCache核心原理之数据结构

Guava Cache的数据结构跟ConcurrentHashMap类似,但也不完全一样。最基本的区别是
ConcurrentMap会一直保存所有添加的元素,直到显式地移除。
相对地,Guava Cache为了限制内存占用,通常都设定为自动回收元素。其数据结构图如下:

在这里插入图片描述

  • LocalCache为Guava Cache的核心类,包含一个Segment数组组成

  • Segement数组的长度决定了cache的并发数

  • 每一个Segment使用了单独的锁,其实每个Segment继承了ReentrantLock,对Segment的写操
    作需要先拿到锁

  • 每个Segment由一个table和5个队列组成

  • 5个队列:
    ReferenceQueue keyReferenceQueue : 已经被GC,需要内部清理的键引用队列
    ReferenceQueue valueReferenceQueue : 已经被GC,需要内部清理的值引用队列
    ConcurrentlinkedQueue<ReferenceEntry<k,v>> recencyQueue : LRU队列,当segment上达到
    临界值发生写操作时该队列会移除数据
    Queue<ReferenceEntry<K, V>> writeQueue:写队列,按照写入时间进行排序的元素队列,写入
    一个元素时会把它加入到队列尾部
    Queue<ReferenceEntry<K, V>> accessQueue:访问队列,按照访问时间进行排序的元素队列,
    访问(包括写入)一个元素时会把它加入到队列尾部

  • 1个table:
    AtomicReferenceArray<ReferenceEntry<K, V>> table:AtomicReferenceArray可以用原子方式
    更新其元素的对象引用数组

  • ReferenceEntry<k,v>
    ReferenceEntry是Guava Cache中对一个键值对节点的抽象,每个ReferenceEntry数组项都是一
    条ReferenceEntry链。并且一个ReferenceEntry包含key、hash、valueReference、next字段
    (单链)
    Guava Cache使用ReferenceEntry接口来封装一个键值对,而用ValueReference来封装Value值

guava cache的数据结构的构建流程:

1)构建CacheBuilder实例cacheBuilder

2)cacheBuilder实例指定缓存器LocalCache的初始化参数

3)cacheBuilder实例使用build()方法创建LocalCache实例(简单说成这样,实际上复杂一些)

3.1)首先为各个类变量赋值(通过第二步中cacheBuilder指定的初始化参数以及原本就定义好的一堆常量)

3.2)之后创建Segment数组

3.3)最后初始化每一个Segment[i]

3.3.1)为Segment属性赋值

3.3.2)初始化Segment中的table,即一个ReferenceEntry数组(每一个key-value就是一个ReferenceEntry)

3.3.3)根据之前类变量的赋值情况,创建相应队列,用于LRU缓存回收算法

GuavaCache核心原理之回收机制

Guava Cache提供了三种基本的缓存回收方式:

  • 基于容量回收
    在缓存项的数目达到限定值之前,采用LRU的回收方式
  • 定时回收
    expireAfterAccess:缓存项在给定时间内没有被读/写访问,则回收。回收顺序和基于大小回收一
    样(LRU)
    expireAfterWrite:缓存项在给定时间内没有被写访问(创建或覆盖),则回收
  • 基于引用回收
    通过使用弱引用的键、或弱引用的值、或软引用的值,Guava Cache可以垃圾回收

除了以上三种还有主动删除,采用命令,这个前面讲了
GuavaCache构建的缓存不会"自动"执行清理和回收工作,也不会在某个缓存项过期后马上清理,也没
有诸如此类的清理机制。
GuavaCache是在每次进行缓存操作的时候,惰性删除 如get()或者put()的时候,判断缓存是否过期

GuavaCache核心原理之Segment定位

先通过key做hash定位到所在的Segment
通过位运算找首地址的偏移量 SegmentCount>=并发数且为2的n次方

V get(K key, CacheLoader<? super K, V> loader) throws ExecutionException {
// 注意,key不可为空
int hash = hash(checkNotNull(key));
// 通过hash定位到segment数组的某个Segment元素,然后调用其get方法
return segmentFor(hash).get(key, hash, loader);
}

再找到segment中的Entry链数组,通过key的hash定位到某个Entry节点

V get(K key, int hash, CacheLoader<? super K, V> loader) throws
ExecutionException {
checkNotNull(key);
checkNotNull(loader);
try {
if (count != 0) { // read-volatile
// 内部也是通过找Entry链数组定位到某个Entry节点
ReferenceEntry<K, V> e = getEntry(key, hash);
......
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值