适用性

  缓存在很多场景下都是相当有用的。例如,计算或检索一个值的代价很高,并且对同样的输入需要不止一次获取值的时候,就应当考虑使用缓存

  Guava Cache与ConcurrentMap很相似,但也不完全一样。最基本的区别是ConcurrentMap会一直保存所有添加的元素,直到显式地移除。相对地,Guava Cache为了限制内存占用,通常都设定为自动回收元素。在某些场景下,尽管LoadingCache 不回收元素,它也是很有用的,因为它会自动加载缓存

  通常来说,Guava Cache适用于:

    • 你愿意消耗一些内存空间来提升速度。
    • 你预料到某些键会被查询一次以上。
    • 缓存中存放的数据总量不会超出内存容量。(Guava Cache是单个应用运行时的本地缓存。它不把数据存放到文件或外部服务器。如果这不符合你的需求,请尝试Redis这类工具)

  如果你的场景符合上述的每一条,Guava Cache就适合你。

  如果你不需要Cache中的特性,使用ConcurrentHashMap有更好的内存效率——但Cache的大多数特性都很难基于旧有的ConcurrentMap复制,甚至根本不可能做到

代码详解

  1. 1 /**
  2. 2 * @author LiuHuan
  3. 3 * @date 2020-06-17 15:52
  4. 4 * @desc Guava Cache学习
  5. 5 */
  6. 6 public class GuavaCacheTest {
  7. 7
  8. 8 public static void main(String[] args) throws ExecutionException {
  9. 9 GuavaCacheTest test = new GuavaCacheTest();
  10. 10 Cache<String, String> cache = test.getGuavaCache();
  11. 11 // 放入/覆盖一个缓存
  12. 12 cache.put("key", "value");
  13. 13 // 获取一个缓存,如果该缓存不存在则返回一个null值
  14. 14 cache.getIfPresent("");
  15. 15 // 获取缓存,当缓存不存在时,则通Callable进行加载并返回。该操作是原子
  16. 16 cache.get("key", () -> loadingValue("key"));
  17. 17 // 回收key为k1的缓存
  18. 18 cache.invalidate("key");
  19. 19 // 使用Map的put方法进行覆盖刷新
  20. 20 cache.asMap().put("key", "value");
  21. 21 // 使用ConcurrentMap的replace方法进行覆盖刷新
  22. 22 cache.asMap().replace("key", "value1");
  23. 23 // 使用Map的putAll方法进行批量覆盖刷新
  24. 24 Map<String,String> needRefresh = ImmutableMap.of("key1","value1", "key2", "value2");
  25. 25 cache.asMap().putAll(needRefresh);
  26. 26 // 批量回收key为key1、key2的缓存
  27. 27 List<String> needInvalidateKeys = Arrays.asList("key1", "key2");
  28. 28 cache.invalidateAll(needInvalidateKeys);
  29. 29 // 回收所有缓存
  30. 30 cache.invalidateAll();
  31. 31
  32. 32 // 用来开启Guava Cache的统计功能。统计打开后,Cache.stats()方法会返回CacheStats对象
  33. 33 CacheStats stats = cache.stats();
  34. 34 // 缓存命中率
  35. 35 double hitRate = stats.hitRate();
  36. 36 // 加载新值的平均时间,单位为纳秒
  37. 37 double averageLoadPenalty = stats.averageLoadPenalty();
  38. 38 // 缓存项被回收的总数,不包括显式清除
  39. 39 long evictionCount = stats.evictionCount();
  40. 40
  41. 41 LoadingCache<String, String> loadingCache = test.getGuavaLoadingCache();
  42. 42 // loadingCache 在进行刷新时无需显式的传入value
  43. 43 loadingCache.refresh("key");
  44. 44 }
  45. 45
  46. 46 /**
  47. 47 * 获取GuavaCache实例
  48. 48 * @return
  49. 49 */
  50. 50 public Cache<String, String> getGuavaCache(){
  51. 51 // 异步触发监听器
  52. 52 RemovalListener<Object, Object> removalListener = RemovalListeners.asynchronous(removal -> {
  53. 53 // 如果被显示移除这里为true
  54. 54 boolean wasEvicted = removal.wasEvicted();
  55. 55 // 移除的原因
  56. 56 RemovalCause cause = removal.getCause();
  57. 57 }, Executors.newSingleThreadExecutor());
  58. 58
  59. 59 // 通过CacheBuilder构建一个缓存实例
  60. 60 Cache<String, String> cache = CacheBuilder.newBuilder()
  61. 61 // 由于Guava的缓存使用了分离锁的机制,扩容的代价非常昂贵,所以合理的初识容量能够减少扩容次数
  62. 62 .initialCapacity(100)
  63. 63 // 设置缓存的最大条数
  64. 64 .maximumSize(100)
  65. 65 // maximumWeight逻辑上用来表示一种“权重”,这里与maximumSize冲突,设置一个即可
  66. 66 // 这里我们将key和value所占的字节数,作为weight,当cache中所有的“weight”总和达到maximumWeight时,将会触发“剔除策略”
  67. 67 .maximumWeight(1024 * 1024)
  68. 68 .weigher((Weigher<String, String>)(key, value) -> key.getBytes().length + value.getBytes().length)
  69. 69 // 使用弱引用存储键。当键没有其它(强或软)引用时,该缓存可能会被回收
  70. 70 .weakKeys()
  71. 71 // 使用弱引用存储值。当值没有其它(强或软)引用时,该缓存可能会被回收
  72. 72 .weakValues()
  73. 73 // 使用软引用存储值。当内存不足并且该值其它强引用引用时,该缓存就会被回收
  74. 74 // 通过软/弱引用的回收方式,相当于将缓存回收任务交给了GC,使得缓存的命中率变得十分的不稳定,在非必要的情况下,还是推荐基于数量和容量的回收
  75. 75 .softValues()
  76. 76 // 设置缓存在写入一分钟后失效
  77. 77 .expireAfterWrite(1, TimeUnit.MINUTES)
  78. 78 // 设置缓存最后一次访问10分钟之后失效,与session类似。与expireAfterWrite冲突,设置一个即可
  79. 79 .expireAfterAccess(Duration.ofMinutes(10))
  80. 80 // 开启缓存统计
  81. 81 .recordStats()
  82. 82 // 设置并发级别为CPU核心数
  83. 83 .concurrencyLevel(Runtime.getRuntime().availableProcessors())
  84. 84 // 移除监听器,这里是移除缓存时同步调用,会拖慢正常的请求
  85. 85 .removalListener(removal -> {
  86. 86 // 如果被显示移除这里为true
  87. 87 boolean wasEvicted = removal.wasEvicted();
  88. 88 // 移除的原因
  89. 89 RemovalCause cause = removal.getCause();
  90. 90 })
  91. 91 // 异步触发监听器
  92. 92 .removalListener(removalListener)
  93. 93 .build();
  94. 94 return cache;
  95. 95 }
  96. 96
  97. 97 /**
  98. 98 * 获取GuavaLoadingCache实例,会有默认的缓存加载策略
  99. 99 * @return
  100. 100 */
  101. 101 public LoadingCache<String, String> getGuavaLoadingCache(){
  102. 102 // 通过CacheBuilder构建一个缓存实例
  103. 103 LoadingCache<String, String> cache = CacheBuilder.newBuilder()
  104. 104 // 设置缓存在写入10分钟后,通过CacheLoader的load方法进行刷新
  105. 105 .refreshAfterWrite(Duration.ofMinutes(10))
  106. 106 .build(new CacheLoader<String, String>() {
  107. 107 @Override
  108. 108 public String load(String key) throws Exception {
  109. 109 // 缓存加载策略
  110. 110 return loadingValue(key);
  111. 111 }
  112. 112
  113. 113 });
  114. 114 return cache;
  115. 115 }
  116. 116
  117. 117 /**
  118. 118 * 缓存加载策略
  119. 119 * @param key
  120. 120 * @return
  121. 121 */
  122. 122 private static String loadingValue(String key){
  123. 123 return null;
  124. 124 };
  125. 125
  126. 126 }

缓存清理  

  使用CacheBuilder构建的缓存不会"自动"执行清理和回收工作,也不会在某个缓存项过期后马上清理,也没有诸如此类的清理机制。相反,它会在写操作时顺带做少量的维护工作,如果写操作实在太少的话,偶尔在读操作时做这个操作。这样做的原因在于:如果要自动地持续清理缓存,就必须有一个线程,这个线程会和用户操作竞争共享锁。此外,某些环境下线程创建可能受限制,这样CacheBuilder就不可用了。

  如果你的缓存是高吞吐的,那就无需担心缓存的维护和清理等工作。如果你的缓存只会偶尔有写操作,而你又不想清理工作阻碍了读操作,那么可以创建自己的维护线程,以固定的时间间隔调用Cache.cleanUp()ScheduledExecutorService可以帮助你很好地实现这样的定时调度

Guava Cache详解的更多相关文章

  1. (转)MyISAM Key Cache详解及优化

    原文:http://huanghualiang.blog.51cto.com/6782683/1372721 一.MyISAM Key Cache详解: 为了最小化磁盘I/O,MyISAM将最频繁访问 ...

  2. HttpContext.Cache 详解

    提到HttpContext.Cache必然会想到Application,他们有什么共性和不同点呢,我们一一道来 相同点: 1.两者都是使用键值对来存储对象 2.两者都是应用程序同生命周期(在cache ...

  3. HTML5应用程序缓存Application Cache详解

    什么是Application Cache HTML5引入了应用程序缓存技术,意味着web应用可进行缓存,并在没有网络的情况下使用,通过创建cache manifest文件,可以轻松的创建离线应用. A ...

  4. 离线应用Application Cache详解

    特点:     1.离线可访问            - 没有网络仍可访问整个应用     2.很小的服务器负载  - 缓存在本地,不需要到服务器请求     3.高速                 ...

  5. spring cache 详解

    Spring使用Cache 从3.1开始,Spring引入了对Cache的支持.其使用方法和原理都类似于Spring对事务管理的支持.Spring Cache是作用在方法上的,其核心思想是这样的:当我 ...

  6. 使用Free命令查看Linux服务器内存使用状况(-/+ buffers/cache详解)

    free命令可选参数 -b,-k,-m,-g show output in bytes, KB, MB, or GB -h human readable output (automatic unit ...

  7. HTML5应用程序缓存Application Cache详解.RP

    什么是Application Cache HTML5引入了应用程序缓存技术,意味着web应用可进行缓存,并在没有网络的情况下使用,通过创建cache manifest文件,可以轻松的创建离线应用. A ...

  8. Oracle内存详解之 Library cache 库缓冲

    Oracle内存详解之 Library cache 库缓冲 2017年11月09日 11:38:39 阅读数:410更多 个人分类: 体系结构 Library cache是Shared pool的一部 ...

  9. Spring Boot 2.x基础教程:进程内缓存的使用与Cache注解详解

    随着时间的积累,应用的使用用户不断增加,数据规模也越来越大,往往数据库查询操作会成为影响用户使用体验的瓶颈,此时使用缓存往往是解决这一问题非常好的手段之一.Spring 3开始提供了强大的基于注解的缓 ...

随机推荐

  1. Python 为什么没有 void 关键字?

    void 是编程语言中最常见的关键字之一,从字面上理解,它是"空的.空集.空白"的意思,最常用于 表示函数的一种返回值类型. 维基百科上有一个定义: The void type, ...

  2. 操作系统-进程(3)Linux下的进程相关命令

    操作系统给予这个内存中的单元一个标识符(PID)依据登入者的UID/GID(/etc/passwd) 衍生出的其它程序(子程序),一般情况也,也会沿用这个程序(父程序)的相关权限 ParentID(P ...

  3. Linux调用Kaggle API下载数据

    1. 登录Kaggle账户,点击My Account 2. Create New API Token得到kaggle.json 3. pip install kaggle 4. 执行kaggle会报错 ...

  4. ClickHouse和他的朋友们(9)MySQL实时复制与实现

    本文转自我司大神 BohuTANG的博客 . 很多人看到标题还以为自己走错了夜场,其实没有. ClickHouse 可以挂载为 MySQL 的一个从库 ,先全量再增量的实时同步 MySQL 数据,这个 ...

  5. python 四位玫瑰数 + 100以内素数求和

    四位玫瑰数 描述‪‬‪‬‪‬‪‬‪‬‮‬‫‬‪‬‪‬‪‬‪‬‪‬‪‬‮‬‪‬‫‬‪‬‪‬‪‬‪‬‪‬‮‬‪‬‭‬‪‬‪‬‪‬‪‬‪‬‮‬‫‬‮‬‪‬‪‬‪‬‪‬‪‬‮‬‪‬‭‬‪‬‪‬‪‬‪‬‪‬‮‬ ...

  6. 【Nginx】如何基于主从模式搭建Nginx+Keepalived双机热备环境?这是最全的一篇了!!

    写在前面 最近出版了<海量数据处理与大数据技术实战>,详情可以关注 冰河技术 微信公众号,查看<我的<海量数据处理与大数据技术实战>出版啦!>一文. 也有不少小伙伴 ...

  7. Android开发之java代码中获取当前系统的时间工具类

    /** * 获取当前时间 * * @return */ public String getTime() { Date date = new Date();// 创建一个时间对象,获取到当前的时间 Si ...

  8. NGUI 优化

    1. Update Ngui 组件继承关系是  UIWidget : UIRect : MonoBehaviour. 因此由每个组件的独自调用update变更为,由某个更新点,统一调用会效率提升.并且 ...

  9. Guava Retrying

    目录 依赖 使用demo RetryerBuilder 实现callable接口 调用 git 参考 依赖 <dependency> <groupId>com.github.r ...

  10. Java8 ParallelStream

    ParallelStream 并行流就是一个把内容拆分成多个数据块,用不同线程分别处理每个数据块的流.对收集源调用parallelStream方法就能将集合转换为并行流. 并行流 并行流和顺序流转换 ...