此文已由作者赵计刚授权网易云社区发布。

欢迎访问网易云社区,了解更多网易技术产品运营经验。

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),实现三步原子操作*/@Nullablefinal CacheLoader<? super K, V> defaultLoader;/** 默认的缓存加载器,用于做一些缓存加载操作(其实就是load),实现三步原子操作*/@Nullablefinal 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个缓存entryint initialCapacity = Math.min(builder.getInitialCapacity(),MAXIMUM_CAPACITY);int segmentShift = 0;int segmentCount = 1;//循环条件的&&后边的内容是关于weight的,由于没有设置maxWeight,所以其值为-1-->evictsBySize()返回falsewhile (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/segmentCountif (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 weightslong 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)相关推荐

  1. Google guava cache源码解析1--构建缓存器(3)

    此文已由作者赵计刚授权网易云社区发布. 欢迎访问网易云社区,了解更多网易技术产品运营经验. 下面介绍在LocalCache(CacheBuilder, CacheLoader)中调用的一些方法: Ca ...

  2. [源码解析] PyTorch分布式优化器(1)----基石篇

    [源码解析] PyTorch分布式优化器(1)----基石篇 文章目录 [源码解析] PyTorch分布式优化器(1)----基石篇 0x00 摘要 0x01 从问题出发 1.1 示例 1.2 问题点 ...

  3. Spring MVC源码解析——HandlerMapping(处理器映射器)

    Sping MVC 源码解析--HandlerMapping处理器映射器 1. 什么是HandlerMapping 2. HandlerMapping 2.1 HandlerMapping初始化 2. ...

  4. postgres 源码解析25 缓冲池管理器-3

      本文讲解缓冲块的选择策略BufferAlloc,同时该函数也是替换策略的核心函数, 知识回顾: postgres源码解析 缓冲池管理–1 postgres源码解析 缓冲池管理–2 总结<执行 ...

  5. postgres 源码解析11 CLOG管理器--2

      在本小节中,着重讲解CLOG日志的读写操作,获取事务的状态信息进行可见性判断内容,相关背景知识见回顾通道: 1 postgres CLOG源码解析-1 2 postgres源码分析 Slru缓冲池 ...

  6. 2.MyBatis源码解析-SqlSession构建流程--阿呆中二

    SqlSession构建流程 MyBatis SqlSession构建流程 与我联系 MyBatis 本文是对mybatis 3.x源码深度解析与最佳实践学习的总结,包括XML文件解析流程.SqlSe ...

  7. OkHttp 3.x 源码解析之Dispatcher分发器

    Dispatcher概念 Dispatcher中文是分发器的意思,和拦截器不同的是分发器不做Aaction事件处理.只做事件流向.在Okhttp中Dispatcher负责将每一次Requst进行分发, ...

  8. postgres 源码解析9 CLOG管理器--1

    1 背景介绍   在Postgres数据库的日志管理系统中,采用CLOG日志记录集群中每个事务的最终状态,在内存中形式是基于SLRU缓冲实现的,有兴趣的回顾下SLRU相关知识:   1 postgre ...

  9. Google Archive Patch 源码解析

    如果你觉得本篇文章太长,可以直接看我总结的结论: Google Archive Patch是严格的基于Zip文件格式的差量算法,其核心生成差量的算法还是BsDiff,核心合成文件的算法还是BsPatc ...

最新文章

  1. ESP8266 WiFi串口模块的学习与使用(一)
  2. Scala教程之:Scala基础
  3. 笔记本电脑怎么清理灰尘_手机声音越用越小怎么办?一段黑科技音波就能清理扬声器灰尘...
  4. CSS3-06 样式 5
  5. GJM:用C#实现网络爬虫(一) [转载]
  6. ehcache 的 diskStore path
  7. 微软发布 Autodesk FBX 漏洞带外安全公告,将于5月推出补丁
  8. VR:下一个技术风口
  9. C语言模块化编程的代码示例
  10. ultraISO方式制作win10安装U盘
  11. 如果你毕业想进央企, 那就选这些大学, 性价比很高
  12. kafka之重新分配分区副本kafka-reassign-partitions命令
  13. XSS Challenges xss-quiz.int21h.jp
  14. android 无法后台运行,安卓模拟器无法后台?
  15. Java程序的编辑、编译、运行
  16. MailRaider Pro for Mac(Outlook邮件格式转换工具) v3.5.0永久激活
  17. 【刷题日记】网易——丰收
  18. 认知学派用计算机来比拟人,心理学基础习题答案
  19. 设计一个圆形文字LOGO
  20. zx1 android版本,索尼NW-ZX100在国内上市 一台非Android的ZX1你愿意尝试吗?

热门文章

  1. android actionbaractivity 错误,Android studio无法解析ActionBarActivity
  2. petalinux 下使用 xsa 查看所有的 Zynq Reg 设置
  3. lol服务器显示未知错误,运行英雄联盟出现未知错误的处理方法
  4. Java面对对象的核心是啥_Java面向对象核心技能
  5. python rpc 性能比较_Python与RPC -- (转)
  6. cadence一些术语
  7. dump mysql_mysql/mariadb知识点总结(28):mysql备份工具之mysqldump
  8. matlab nargout
  9. (亲测可行)基于面绘制的MC算法以及基于体绘制的 Ray-casting 实现Dicom图像的三维重建(python实现)
  10. FPGA之道(41)HDL的三种描述方式