更新时间:2022-06-09 00:51:02
Google开源的Java重用工具集库Guava里的一款缓存工具,实现的缓存功能:
Guava Cache架构设计源于ConcurrentHashMap,简单场景下可自行编码通过HashMap做少量数据的缓存。
但若结果可能随时间改变或希望存储的数据空间可控,***自己实现这种数据结构。
使用多个segments方式的细粒度锁,在保证线程安全的同时,支持高并发场景需求。
Cache类似Map,是存储K.V对的集合,不过它还需处理evict、expire、dynamic load等算法逻辑,需要一些额外信息实现这些操作,需做方法与数据的关联封装。
Cache由多个Segment组成,而每个Segment包含一个ReferenceEntry数组:
volatile @MonotonicNonNull AtomicReferenceArray<ReferenceEntry<K, V>> table;
每个ReferenceEntry数组项都是一条ReferenceEntry链。
一个ReferenceEntry包含key、hash、value Reference、next字段,除了在ReferenceEntry数组项中组成的链。
ReferenceEntry可以是强引用类型的key,也可以WeakReference类型的key,为了减少内存使用量,还可以根据是否配置了expireAfterWrite、expireAfterAccess、maximumSize来决定是否需要write链和access链确定要创建的具体Reference:StrongEntry、StrongWriteEntry、StrongAccessEntry、StrongWriteAccessEntry等。
map中节点可处于如下状态:
有效的:
无效的:
Value的引用
之所以用Reference命令,是因为Cache要支持:
ValueReference 因为Cache支持强引用的Value、SoftReference Value以及WeakReference Value,因而它对应三个实现类:StrongValueReference、SoftValueReference、WeakValueReference。
为支持动态加载机制,它还有一个LoadingValueReference,需动态加载一个key的值时:
ValueReference对象中会保留对ReferenceEntry的引用,这是因为在Value因为WeakReference、SoftReference被回收时,需要使用其key将对应的项从Segment的table中移除。
在一个Segment中,所有ReferenceEntry还组成:
为了实现LRU,Guava Cache在Segment中添加的这两条链,都是双向链表,通过ReferenceEntry中的如下链接而成:
previousInWriteQueue
nextInWriteQueue
previousInAccessQueue
nextInAccessQueue
WriteQueue和AccessQueue都自定义了offer、peek、remove、poll等操作:
offer操作,若是:
remove操作:
直接从该链中移除该节点
poll操作:
将头节点的下一个节点移除,并返回。