Guava Cache缓存设计原理,java基础入门

HarmonyOS学习 2021-11-25 18:26:03
java 面试 编程语言 后端开发

每个ReferenceEntry数组项都是一条ReferenceEntry链。

Guava Cache缓存设计原理,java基础入门_面试

一个ReferenceEntry包含key、hash、value Reference、next字段,除了在ReferenceEntry数组项中组成的链。

ReferenceEntry可以是强引用类型的key,也可以WeakReference类型的key,为了减少内存使用量,还可以根据是否配置了expireAfterWrite、expireAfterAccess、maximumSize来决定是否需要write链和access链确定要创建的具体Reference:StrongEntry、StrongWriteEntry、StrongAccessEntry、StrongWriteAccessEntry等。

 ReferenceEntry接口

  • reference map中的节点

Guava Cache缓存设计原理,java基础入门_面试_02

map中节点可处于如下状态:

有效的:

  • Live:设置了有效的键/值

  • Loading:加载中

无效的:

  • Expired:时间已过(键/值仍可设置)

  • Collected:键/值已部分收集,但尚未清理

  • Unset:标记为未设置,等待清理或重用

 ValueReference

Value的引用

Guava Cache缓存设计原理,java基础入门_面试_03

之所以用Reference命令,是因为Cache要支持:

  • WeakReference K

  • SoftReference、WeakReference V

ValueReference 因为Cache支持强引用的Value、SoftReference Value以及WeakReference Value,因而它对应三个实现类:StrongValueReference、SoftValueReference、WeakValueReference。

 LoadingValueReference

为支持动态加载机制,它还有一个LoadingValueReference,需动态加载一个key的值时:

  • 先把该值封装在LoadingValueReference,以表达该key对应的值已经在加载

  • 若其它线程也要查询该key对应的值,就能得到该引用,并且等待该值加载完成,以保证该值只被加载一次

  • 在该值加载完成后,将LoadingValueReference替换成其他ValueReference类型

ValueReference对象中会保留对ReferenceEntry的引用,这是因为在Value因为WeakReference、SoftReference被回收时,需要使用其key将对应的项从Segment的table中移除。

 Queue

在一个Segment中,所有ReferenceEntry还组成:

  • access链(accessQueue)

  • write链(writeQueue)

为了实现LRU,Guava Cache在Segment中添加的这两条链,都是双向链表,通过ReferenceEntry中的如下链接而成:

  • previousInWriteQueue

  • nextInWriteQueue

  • previousInAccessQueue

  • nextInAccessQueue

 WriteQueue

Guava Cache缓存设计原理,java基础入门_Java_04

 AccessQueue

Guava Cache缓存设计原理,java基础入门_面试_05

WriteQueue和AccessQueue都自定义了offer、peek、remove、poll等操作:

Guava Cache缓存设计原理,java基础入门_后端开发_06

offer操作,若是:

  • 新增节点

直接加到该链的结尾

  • 已存在的节点

将该节点链接的链尾

remove操作:

直接从该链中移除该节点

poll操作:

将头节点的下一个节点移除,并返回。

 缓存相关操作


 Segment的evict清除策略


在每次调用操作的开始和结束时触发清理工作,这样比一般的缓存另起线程监控清理相比,可减少开销。

但若长时间没有调用方法,会导致不能及时清理释放内存空间。

evict主要处理四个Queue:

  • keyReferenceQueue

  • valueReferenceQueue

  • writeQueue

  • accessQueue

前两个queue是因为WeakReference、SoftReference被垃圾回收时加入的,清理时只需遍历整个queue,将对应项从LocalCache移除即可:

  • keyReferenceQueue存放ReferenceEntry

  • valueReferenceQueue存放的是ValueReference

要从Cache中移除需要有key,因而ValueReference需要有对ReferenceEntry的引用。

后两个Queue,只需检查是否配置了相应的expire时间,然后从头开始查找已经expire的Entry,将它们移除。

Segment中的put操作:put操作相对比较简单,首先它需要获得锁,然后尝试做一些清理工作,接下来的逻辑类似ConcurrentHashMap中的rehash,查找位置并注入数据。需要说明的是当找到一个已存在的Entry时,需要先判断当前的ValueRefernece中的值事实上已经被回收了,因为它们可以是WeakReference、SoftReference类型,如果已经被回收了,则将新值写入。并且在每次更新时注册当前操作引起的移除事件,指定相应的原因:COLLECTED、REPLACED等,这些注册的事件在退出的时候统一调用Cache注册的RemovalListener,由于事件处理可能会有很长时间,因而这里将事件处理的逻辑在退出锁以后才做。最后,在更新已存在的Entry结束后都尝试着将那些已经expire的Entry移除。另外put操作中还需要更新writeQueue和accessQueue的语义正确性。

Segment带CacheLoader的get操作

V get(K key, int hash, CacheLoader<? super K, V> loader) throws ExecutionException {

checkNotNull(key);

checkNotNull(loader);

try {

if (count != 0) { // read-volatile

// don’t call getLiveEntry, which would ignore loading values

ReferenceEntry<K, V> e = getEntry(key, hash);

if (e != null) {

long now = map.ticker.read();

V value = getLiveValue(e, now);

if (value != null) {

recordRead(e, now);

statsCounter.recordHits(1);

return scheduleRefresh(e, key, hash, value, now, loader);

}

ValueReference<K, V> valueReference = e.getValueReference();

if (valueReference.isLoading()) {

return waitForLoadingValue(e, key, valueReference);

}

}

}

// at this point e is either null or expired;

return lockedGetOrLoad(key, hash, loader);

} catch (ExecutionException ee) {

Throwable cause = ee.getCause();

if (cause instanceof Error) {

throw new ExecutionError((Error) cause);

} else if (cause instanceof RuntimeException) {

throw new UncheckedExecutionException(cause);

}

throw ee;

} finally {

postReadCleanup();

}

}

1. 先查找table中是否已存在没有被回收、也没有expire的entry,如果找到,并在CacheBuilder中配置了refreshAfterWrite,并且当前时间间隔已经操作这个事件,则重新加载值,否则,直接返回原有的值

2. 如果查找到的ValueReference是LoadingValueReference,则等待该LoadingValueReference加载结束,并返回加载的值

Guava Cache缓存设计原理,java基础入门_面试_07

3. 如果没有找到entry,或者找到的entry的值为null,则加锁后,继续在table中查找已存在key对应的entry,如果找到并且对应的entry.isLoading()为true,则表示有另一个线程正在加载,因而等待那个线程加载完成,如果找到一个非null值,返回该值,否则创建一个LoadingValueReference

Guava Cache缓存设计原理,java基础入门_Java_08

并调用loadSync加载相应的值

Guava Cache缓存设计原理,java基础入门_Java_09

在加载完成后,将新加载的值更新到table中,即大部分情况下替换原来的LoadingValueReference

 CacheBuilder

学习分享,共勉

这里是小编拿到的学习资源,其中包括“中高级Java开发面试高频考点题笔记300道.pdf”和“Java核心知识体系笔记.pdf”文件分享,内容丰富,**囊括了JVM、锁、并发、Java

《一线大厂Java面试题解析+后端开发学习笔记+最新架构讲解视频+实战项目源码讲义》

【docs.qq.com/doc/DSmxTbFJ1cmN1R2dB】 完整内容开源分享

反射、Spring原理、微服务、Zookeeper、数据库、数据结构等大量知识点。同时还有Java进阶学习的知识笔记脑图(内含大量学习笔记)!**

资料整理不易,读者朋友可以转发分享下!

Java核心知识体系笔记.pdf

Guava Cache缓存设计原理,java基础入门_面试_10

中高级Java开发面试高频考点题笔记300道.pdf

Guava Cache缓存设计原理,java基础入门_Java_11

架构进阶面试专题及架构学习笔记脑图

Guava Cache缓存设计原理,java基础入门_面试_12

Java架构进阶学习视频分享

本文已被 CODING开源项目:【一线大厂Java面试题解析+核心总结学习笔记+最新讲解视频+实战项目源码】收录

版权声明
本文为[HarmonyOS学习]所创,转载请带上原文链接,感谢
https://blog.51cto.com/u_15438507/4690462

  1. Java经典面试题详解,突围金九银十面试季(附详细答案,mysql集群架构部署方案
  2. java整理,java高级特性编程及实战第一章
  3. java教程——反射,mongodb下载教程
  4. Java岗大厂面试百日冲刺 - 日积月累,每日三题【Day12,zookeeper原理作用
  5. Java后端互联网500道中高级面试题(含答案),linux钩子技术
  6. java8 Stream API及常用方法,java初级程序员面试
  7. java-集合-Map(双列)——迪迦重制版,2021Java开发社招面试解答之性能优化
  8. Flink处理函数实战之二:ProcessFunction类,java线程面试题目
  9. flex 布局详解,【Java面试题
  10. Linux basic command learning
  11. Why did docker lose to kubernetes? Docker employee readme!
  12. MySQL安装
  13. Elastic Search Aggregate Learning five: Problem Analysis of Uncertainty of sequencing results, Alibaba Java Performance Tuning Practical
  14. Installing, configuring, starting and accessing rabbitmq under Linux
  15. Oracle SQL injection summary
  16. Installation MySQL
  17. L'exposition à la photo d'essai sur la route i7 du nouveau vaisseau amiral de BMW Pure Electric a également été comparée à celle de Xiaopeng p7.
  18. spring JTA 关于异常处理的时机问题
  19. Le problème du temps de traitement des exceptions dans la JTA printanière
  20. Flink Handling Function Real War II: processfunction class, Java thread interview subject
  21. Oracle SQL injection summary
  22. [Java data structure] you must master the classic example of linked list interview (with super detailed illustration and code)
  23. Do you really know MySQL order by
  24. Record a java reference passing problem
  25. spring JTA 關於异常處理的時機問題
  26. Java - Set - Map (double file) - dija Rewriting, 2021 Java Developer's Performance Optimization
  27. Android入门教程 | OkHttp + Retrofit 取消请求的方法
  28. Java 8 Stream API and common methods, Java Junior Program interview
  29. Github 疯传!史上最强!BAT 大佬,2021年最新Java大厂面试笔试题分享
  30. git(3)Git 分支,zookeeper下载教程
  31. Java Backend Internet 500 questions d'entrevue moyennes et avancées (y compris les réponses), technologie de crochet Linux
  32. Entretien d'entretien d'usine Java post sprint de 100 jours - accumulation de jours et de mois, trois questions par jour [jour 12, fonction de principe de Zookeeper
  33. Tutoriel Java - reflection, tutoriel de téléchargement mongodb
  34. How to analyze several common key and hot issues in redis from multiple dimensions
  35. GIT (3) GIT Branch, Zookeeper Download tutoriel
  36. Tutoriel de démarrage Android | okhttp + Retrofit comment annuler une demande
  37. Design pattern [3.3] - Interpretation of cglib dynamic agent source code
  38. Share the actual operation of private collection project nodejs backend + Vue + Mysql to build a management system
  39. Springboot has 44 application initiators
  40. GitHub上霸榜久居不下的《Java面试突击宝典》,java图形用户界面设计基础
  41. GitHub上访问下载破百万的神仙文档《Java面试神技》看完我呆了,java面试问项目中遇到的问题
  42. GitHub上标星75k 超牛的《Java面试突击版,java高级工程师技能
  43. GitHub上标星2,java项目开发实训教程
  44. Docker development environment Preview
  45. JavaScript高級深入淺出:掌握 this 指向
  46. JavaScript Advanced Insight and outside: Mastering this direction
  47. Vue de l'application pratique de Javascript, drop drag Event
  48. docker 安装部署 Jenkins 2.322
  49. kafka安装
  50. 近九万字图文详解RabbitMQ
  51. Engaged in Java for one and a half years, how to break through yourself
  52. 输出9*9乘法表----java
  53. 判断一个数是不是素数-------java
  54. java项目,记录页面修改值,内部打“官司”用
  55. Docker installation Deployment Jenkins 2.322
  56. Comment porter un pantalon en hiver? Les petits hommes, les jambes épaisses et la largeur de l'entrejambe peuvent être vus. 3 techniques pour éviter la foudre
  57. MySQL下载和安装教程
  58. In depth analysis of rocketmq source code - message storage module
  59. Spring transaction management
  60. mysql恢复ibd数据,为何频频报错?