Google guava cache源码解析1--构建缓存器(2)
此文已由作者赵计刚授权网易云社区发布。
欢迎访问网易云社区,了解更多网易技术产品运营经验。
CacheBuilder-->maximumSize(long size)
/**
* 指定cache中最多能存放的entry(key-value)个数maximumSize
* 注意:
* 1、在entry个数还未达到这个指定个数maximumSize的时候,可能就会发生缓存回收
* 上边这种情况发生在cache size接近指定个数maximumSize,
* cache就会回收那些很少会再被用到的缓存(这些缓存会使最近没有被用到或很少用到的),其实说白了就是LRU算法回收缓存
* 2、maximumSize与maximumWeight不能一起使用,其实后者也很少会使用
*/
public CacheBuilder<K, V> maximumSize(long size) {
/* 检查maximumSize是否已经被设置过了 */
checkState(this.maximumSize == UNSET_INT,
"maximum size was already set to %s",
this.maximumSize);
/* 检查maximumWeight是否已经被设置过了(这就是上边说的第二条)*/
checkState(this.maximumWeight == UNSET_INT,
"maximum weight was already set to %s",
this.maximumWeight);
/* 这是与maximumWeight配合的一个属性 */
checkState(this.weigher == null,
"maximum size can not be combined with weigher");
/* 检查设置的maximumSize是不是>=0,通常不会设置为0,否则不会起到缓存作用 */
checkArgument(size >= 0, "maximum size must not be negative");
this.maximumSize = size;
return this;
}
注意:
设置整个cache(而非每个Segment)中最多可存放的entry的个数
CacheBuilder-->build(CacheLoader<? super K1, V1> loader)
/**
* 建立一个cache,该缓存器通过使用传入的CacheLoader,
* 既可以获取已给定key的value,也能够自动的计算和获取缓存(这说的就是get(Object key)的三步原子操作)
* 当然,这里是线程安全的,线程安全的运行方式与ConcurrentHashMap一致
*/
public <K1 extends K, V1 extends V> LoadingCache<K1, V1> build(CacheLoader<? super K1, V1> loader) {
checkWeightWithWeigher();
return new LocalCache.LocalLoadingCache<K1, V1>(this, loader);
}
注意:
要看懂该方法,需要了解一些泛型方法的使用方式与泛型限界
该方法的返回值是一个LoadingCache接口的实现类LocalLoadingCache实例
在build方法需要传入一个CacheLoader的实例,实际使用中使用了匿名内部类来实现的,源码的话,就是一个无参构造器,什么也没做,传入CacheLoader实例的意义就是"类结构"部分所说的load()方法
在上边调用build时,整个代码的执行权其实就交给了LocalCache.
3.2、LocalCache
LocalLoadingCahe构造器
static class LocalLoadingCache<K, V> extends LocalManualCache<K, V>
implements LoadingCache<K, V> { LocalLoadingCache(CacheBuilder<? super K, ? super V> builder,
CacheLoader<? super K, V> loader) {
super(new LocalCache<K, V>(builder, checkNotNull(loader)));
}
说明:在该内部类的无参构造器的调用中,
1)首先要保证传入的CacheLoader实例非空,
2)其次创建了一个LocalCache的实例出来,
3)最后调用父类LocalManualCache的私有构造器将第二步创建出来的LocalCache实例赋给LocalCache的类变量,完成初始化。
这里最重要的就是第二步,下面着重讲第二步:
LocalCache的一些属性
/** 最大容量(2的30次方),即最多可存放2的30次方个entry(key-value) */
static final int MAXIMUM_CAPACITY = 1 << 30; /** 最多多少个Segment(2的16次方)*/
static final int MAX_SEGMENTS = 1 << 16; /** 用于选择Segment */
final int segmentMask; /** 用于选择Segment,尽量将hash打散 */
final int segmentShift; /** 底层数据结构,就是一个Segment数组,而每一个Segment就是一个hashtable */
final Segment<K, V>[] segments; /**
* 并发水平,这是一个用于计算Segment个数的一个数,
* Segment个数是一个刚刚大于或等于concurrencyLevel的数
*/
final int concurrencyLevel; /** 键的引用类型(strong、weak、soft) */
final Strength keyStrength; /** 值的引用类型(strong、weak、soft) */
final Strength valueStrength; /** The maximum weight of this map. UNSET_INT if there is no maximum.
* 如果没有设置,就是-1
*/
final long maxWeight; final long expireAfterAccessNanos; final long expireAfterWriteNanos; /** Factory used to create new entries. */
final EntryFactory entryFactory; /** 默认的缓存加载器,用于做一些缓存加载操作(其实就是load),实现三步原子操作*/
@Nullable
final CacheLoader<? super K, V> defaultLoader; /** 默认的缓存加载器,用于做一些缓存加载操作(其实就是load),实现三步原子操作*/
@Nullable
final CacheLoader<? super K, V> defaultLoader;
说明:关于这些属性的含义,看注释+CacheBuilder部分的属性注释+ConcurrentHashMap的属性注释
LocalCache-->LocalCache(CacheBuilder, CacheLoader)
/**
* 创建一个新的、空的map(并且指定策略、初始化容量和并发水平)
*/
LocalCache(CacheBuilder<? super K, ? super V> builder,
@Nullable CacheLoader<? super K, V> loader) {
/*
* 默认并发水平是4,即四个Segment(但要注意concurrencyLevel不一定等于Segment个数)
* Segment个数:一个刚刚大于或等于concurrencyLevel且是2的几次方的一个数
*/
concurrencyLevel = Math
.min(builder.getConcurrencyLevel(), MAX_SEGMENTS); keyStrength = builder.getKeyStrength();//默认为Strong,即强引用
valueStrength = builder.getValueStrength();//默认为Strong,即强引用 // 缓存超时(时间起点:entry的创建或替换(即修改))
expireAfterWriteNanos = builder.getExpireAfterWriteNanos();
// 缓存超时(时间起点:entry的创建或替换(即修改)或最后一次访问)
expireAfterAccessNanos = builder.getExpireAfterAccessNanos();
//创建entry的工厂
entryFactory = EntryFactory.getFactory(keyStrength,
usesAccessEntries(),
usesWriteEntries());
//默认的缓存加载器
defaultLoader = loader; // 初始化容量为16,整个cache可以放16个缓存entry
int initialCapacity = Math.min(builder.getInitialCapacity(),
MAXIMUM_CAPACITY); int segmentShift = 0;
int segmentCount = 1;
//循环条件的&&后边的内容是关于weight的,由于没有设置maxWeight,所以其值为-1-->evictsBySize()返回false
while (segmentCount < concurrencyLevel
&& (!evictsBySize() || segmentCount * 20 <= maxWeight)) {
++segmentShift;
segmentCount <<= 1;//找一个刚刚大于或等于concurrencyLevel的Segment数
}
this.segmentShift = 32 - segmentShift;
segmentMask = segmentCount - 1; this.segments = newSegmentArray(segmentCount);//创建指定大小的数组 int segmentCapacity = initialCapacity / segmentCount;//计算每一个Segment中的容量的值,刚刚大于等于initialCapacity/segmentCount
if (segmentCapacity * segmentCount < initialCapacity) {
++segmentCapacity;
} int segmentSize = 1;//每一个Segment的容量
while (segmentSize < segmentCapacity) {
segmentSize <<= 1;//刚刚>=segmentCapacity&&是2的几次方的数
} if (evictsBySize()) {//由于没有设置maxWeight,所以其值为-1-->evictsBySize()返回false
// Ensure sum of segment max weights = overall max weights
long maxSegmentWeight = maxWeight / segmentCount + 1;
long remainder = maxWeight % segmentCount;
for (int i = 0; i < this.segments.length; ++i) {
if (i == remainder) {
maxSegmentWeight--;
}
this.segments[i] = createSegment(segmentSize,
maxSegmentWeight,
builder.getStatsCounterSupplier().get());
}
} else {
for (int i = 0; i < this.segments.length; ++i) {
this.segments[i] = createSegment(segmentSize,
UNSET_INT,
builder.getStatsCounterSupplier().get());
}
}
}
说明:这里的代码就是整个LocalCache实例的创建过程,非常重要!!!
免费领取验证码、内容安全、短信发送、直播点播体验包及云服务器等套餐
更多网易技术、产品、运营经验分享请点击。
相关文章:
【推荐】 流式断言器AssertJ介绍
Google guava cache源码解析1--构建缓存器(2)的更多相关文章
- Google guava cache源码解析1--构建缓存器(1)
此文已由作者赵计刚授权网易云社区发布. 欢迎访问网易云社区,了解更多网易技术产品运营经验. 1.guava cache 当下最常用最简单的本地缓存 线程安全的本地缓存 类似于ConcurrentHas ...
- 第二章 Google guava cache源码解析1--构建缓存器
1.guava cache 当下最常用最简单的本地缓存 线程安全的本地缓存 类似于ConcurrentHashMap(或者说成就是一个ConcurrentHashMap,只是在其上多添加了一些功能) ...
- Google guava cache源码解析1--构建缓存器(3)
此文已由作者赵计刚授权网易云社区发布. 欢迎访问网易云社区,了解更多网易技术产品运营经验. 下面介绍在LocalCache(CacheBuilder, CacheLoader)中调用的一些方法: Ca ...
- Guava Cache源码解析
概述: 本次主要是分析cache的源码,基本概念官方简介即可. 基本类图: 在官方的文档说明中,Guava Cache实现了三种加载缓存的方式: LoadingCache在构建缓存的时候,使用buil ...
- [源码解析] PyTorch分布式优化器(1)----基石篇
[源码解析] PyTorch分布式优化器(1)----基石篇 目录 [源码解析] PyTorch分布式优化器(1)----基石篇 0x00 摘要 0x01 从问题出发 1.1 示例 1.2 问题点 0 ...
- [源码解析] PyTorch分布式优化器(2)----数据并行优化器
[源码解析] PyTorch分布式优化器(2)----数据并行优化器 目录 [源码解析] PyTorch分布式优化器(2)----数据并行优化器 0x00 摘要 0x01 前文回顾 0x02 DP 之 ...
- [源码解析] PyTorch分布式优化器(3)---- 模型并行
[源码解析] PyTorch分布式优化器(3)---- 模型并行 目录 [源码解析] PyTorch分布式优化器(3)---- 模型并行 0x00 摘要 0x01 前文回顾 0x02 单机模型 2.1 ...
- Guava Cache源码详解
目录 一.引子 二.使用方法 2.1 CacheBuilder有3种失效重载模式 2.2 测试验证 三.源码剖析 3.1 简介 3.2 源码剖析 四.总结 优点: 缺点: 正文 回到顶部 一.引子 缓 ...
- 常用限流算法与Guava RateLimiter源码解析
在分布式系统中,应对高并发访问时,缓存.限流.降级是保护系统正常运行的常用方法.当请求量突发暴涨时,如果不加以限制访问,则可能导致整个系统崩溃,服务不可用.同时有一些业务场景,比如短信验证码,或者其它 ...
随机推荐
- 【WebService】WebService之WSDL文档深入分析(三)
WSDL概念 WSDL(网络服务描述语言,Web Services Description Language)是一门基于 XML 的语言,用于描述 Web Services 以及如何对它们进行访问. ...
- Java的GUI设计小技巧
不可关闭窗口 setDefaultCloseOperation(DO_NOTHING_ON_CLOSE);
- 2019.01.02 洛谷P4512 【模板】多项式除法
传送门 解析 代码: #include<bits/stdc++.h> #define ri register int using namespace std; typedef long l ...
- oracle创建视图(view)
视图:是基于一个表或多个表或视图的逻辑表,本身不包含数据,通过它可以对表里面的数据进行查询和修改.视图基于的表称为基表,Oracle的数据库对象分为五种:表,视图,序列,索引和同义词. 视图是存储在数 ...
- 更新源pip
国内镜像源列表 豆瓣(douban) http://pypi.douban.com/simple/清华大学 https://pypi.tuna.tsinghua.edu.cn/simple/阿里云 h ...
- VC调试小结
本机调试F5: 开始调试Shift+F5: 停止调试F10: 调试到下一句,这里是单步跟踪 F11: 调试到下一句,跟进函数内部Shift+F11: 从当前函数中跳出F9: 设置(取消)断点Outpu ...
- C++STL list
list双向链表 高效进行插入删除数据 不可以随机存取元素,所以不支持at()和[]操作符.it可以++ --,不能it+5 节点序号从0开始 list<int> l; l.push_b ...
- 关于SQL表字段值缺失的处理办法
在计算收益率时候, 收益率 = 收益 / 成本 一.如果成本为0,NULL,此时无法计算收益率: 方法: 1.将成本为0的数据 运算 (case when cost =0 or cost is n ...
- 分分钟搞懂rank() over(partition by)的使用
一.rank() over(partition by ...order by) 解释:partition by用于给结果集分组,如果没有指定那么它把整个结果集作为一个分组. 二.语法:ROW_NUM ...
- Codeforces Round#413 Div.2
A. Carrot Cakes 题面 In some game by Playrix it takes t minutes for an oven to bake k carrot cakes, al ...