Guava LocalCache源码分析:Cache生成
LocalCache为guava本地缓存的解决方案,提供了基于容量,时间和引用的缓存回收方式,其数据读写都在一个进程内,相对与 redis 等分布式缓存,不需要网络传输的过程,访问速度很快,同时也受到 JVM 内存的制约,无法在数据量较多的场景下使用。
基于以上特点,guava cache 的主要应用场景为以下几种:
- 对于访问速度有较大要求
- 存储的数据不经常变化
- 数据量不大,占用内存较小
- 需要访问整个集合
- 能够容忍数据不是实时的
版本
<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
<version>33.2.1-jre</version>
</dependency>
LocalCache参数说明
类型 | 参数名 | 默认值 | 说明 |
---|---|---|---|
static final int | MAXIMUM_CAPACITY | 1 << 30 | 最大容量,如果其中一个具有参数的构造函数隐式指定了更高的值,则使用该容量。必须是2的幂{2^30},以确保Entry可以使用整数进行索引 |
static final int | MAX_SEGMENTS | 1 << 16 | 允许的最大分段数,并发数,这里设置的2^16;用于绑定构造函数参数 |
static final int | CONTAINS_VALUE_RETRIES | 3 | containsValue方法中的(未同步)重试次数 |
static final int | DRAIN_THRESHOLD | 0x3F | 在更新缓存的最近顺序信息之前,每个段可以缓冲的缓存访问操作数。这用于通过记录读取的memento并延迟锁获取,直到超过阈值或发生突变,来避免锁争用 |
static final int | DRAIN_MAX | 16 | 单次清理运行中要排出的最大Entry数。这独立适用于清理队列和两个引用队列 |
static final | logger | Logger.getLogger(LocalCache.class.getName()) | java.util.logging.Logger日志 |
final int | segmentMask | —— | 用于索引分段的掩码值。密钥哈希码的高位用于选择段 |
final int | segmentShift | —— | 分段内索引的移位值。有助于防止最终位于同一段中的Entry也位于同一桶中 |
final Segment<K, V>[] | segments | —— | 每个段都是一个继承了ReentrantLock的哈希表 |
final int | concurrencyLevel | —— | 并发级别 |
final Equivalence<Object> | keyEquivalence | —— | 键比较策略 |
final Equivalence<Object> | valueEquivalence | —— | 值比较策略 |
final Strength | keyStrength | —— | 键策略 |
final Strength | valueStrength | —— | 值策略 |
final long | maxWeight | —— | 此Map的最大容量。如果没有最大值,则返回UNSET_INT |
final Weigher<K, V> | weigher | —— | 缓存容量计算器 |
final long | expireAfterAccessNanos | —— | 在Entry最后一次访问的多久内Map保留该Entry |
final long | expireAfterWriteNanos | —— | 在Entry最后一次写入的多久内Map保留该Entry |
final long | refreshNanos | —— | 当Entry上次写入多久后,Entry成为刷新的候选项。设置自动刷新间隔的 |
final Queue<RemovalNotification<K, V>> | removalNotificationQueue | —— | 存放removalListener占用的Entry的等待队列 |
final RemovalListener<K, V> | removalListener | —— | 当Entry因软/弱Entry的过期或垃圾回收而被删除时调用的监听器 |
final Ticker | ticker | —— | com.google.common.base.Ticker计数器,用于计算时间 |
final EntryFactory | entryFactory | —— | 用于创建新Entry |
final StatsCounter | globalStatsCounter | —— | 全局缓存数。请注意,还有每个分段的实体数量,必须聚合这些分段中的Entry数量才能获得全局总数 |
final CacheLoader<? super K, V> | defaultLoader | —— | 加载操作时使用的默认缓存加载器 |
Cache构建过程
guava cache 最常用的方式是通过 CacheBuilder 进行构建, CacheBuilder 通过 build 方法返回一个new LocalCache.LocalLoadingCache<K1, V1>(this, loader);
其中 LocalLoadingCache 继承了 LocalManualCache,而 LocalManualCache 定义了一个 final LocalCache<K, V>。
最终返回的LocalManualCache的所有操作均为对LocalCache的操作。
LocalCache介绍
LocalCache继承了AbstractMap并实现了ConcurrentMap。
LocalCache基本策略是对Entry分段存储,每个Segment本身都是一个并发可读的哈希表。该映射支持跨不同段的非阻塞读取和并发写入。如果指定了最大大小,则使用页面替换算法对段内的Entry进行替换。