缓存相关总结

  1. Ehcache支持持久化到本地磁盘,Guava不可以;
  2. Ehcache有现成的集群解决方案,Guava没有。不过个人感觉比较鸡肋,对JVM级别的缓存来讲太重了;
  3. Ehcache jar包庞大,Guava Cache只是Guava jar包中的工具之一,而且后者远远小于Ehcache;
  4. 两种缓存当缓存过期或者没有命中的时候都可以通过load接口重载数据,调用方式略有不同。两者的主要区别是Ehcache的缓存load的时候,允许用户返回null,而Guava Cache则不允许返回为null,因为Guava Cache是根据value的值是否为null来判断是否需要load,所以不允许返回为null,但是使用的时候可以使用空对象替换。不允许返回null是一个很好的考虑;
  5. Ehcache有内存占用大小统计,Guava Cache没有,需要自己开发;
  6. Ehcache在put缓存的时候,对K、V都做了包装,对GC有一定影响。

什么时候适用Ehcache、什么时候适用Guava cache?

首先,两者都是很成熟的JVM级别缓存,所以在绝大多数情况都是可以满足要求的。

适用Ehcache的情况

  1. 需要持久化。使用持久化功能需要,缓存稳定,以免持久化的数据不准确影响结果。
  2. 有集群解决方案。

适用Guava cache的情况
Guava cache说简单点就是一个支持LRU的ConCurrentHashMap,它没有Ehcache那么多的各种特性,只是提供了增、删、改、查、刷新规则和时效规则设定等最基本的元素。做一个jar包中的一个功能之一,Guava cache极度简洁并能满足觉大部分人的要求。

总结
Ehcache有着全面的缓存特性,但是略重。Guava cache有最基本的缓存特性,很轻。大家根据具体情况选择使用。

1.Guava Cache简介

Guava cache是一个支持高并发的线程安全的本地缓存。多线程情况下也可以安全的访问或者更新cache。这些都是借鉴了ConcurrentHashMap的结果,不过,guava cache 又有自己的特性

"automatic loading of entries into the cache"

即 :当cache中不存在要查找的entry的时候,它会自动执行用户自定义的加载逻辑,加载成功后再将entry存入缓存并返回给用户未过期的entry,如果不存在或者已过期,则需要load,同时为防止多线程并发下重复加载,需要先锁定,获得加载资格的线程(获得锁的线程)创建一个LoadingValueRefrerence并放入map中,其他线程等待结果返回。

2.2 LoadingCache

LoadingCache是附带CacheLoader构建而成的缓存实现。创建自己的CacheLoader通常只需要简单地实现load()方法

2.3 CallableCache

CallableCache的方式最大的特点在于可以在get的时候动态的指定load的数据源:

3.源码剖析

3.1 Guava Cache类图结构

3.2 LocalCache

Guava Cache中的核心类,数据结构图如下所示:

通过上图可以看出,LocalCache的数据结构与ConcurrentHashMap很相似,采用了分段策略,通过减小锁的粒度来提高并发 ,LocalCache中数据存储在Segment[]中,每个segment又包含5个队列和一个table,这个table是自定义的一种类数组的结构,每个元素都包含一个ReferenceEntry<k,v>链表,指向next entry。这些队列,前2个是key、value引用队列用以加速GC回收,后3个队列记录用户的写记录、访问记录、高频访问顺序队列用以实现LRU算法。AtomicReferenceArray是JUC包下的Doug Lea老李头设计的类:一组对象引用,其中元素支持原子性更新。这种实现比ConcurrentHashMap要复杂的多,除了多了5个引用队列之外,并且采用了ReferenceEntry的方式,引用数据存储接口,默认强引用,具体类图如下

3.3 回收策略

前面说到Guava Cache与ConcurrentHashMap很相似,包括其并发策略,数据结构等,但也不完全一样。最基本的区别是ConcurrentHashMap会一直保存所有添加的元素,直到显式地移除,而guava cache可以自动回收元素,这在某种情况下可以更好优化资源,避免浪费的情况。

3.3.1 缓存回收方式

  • 基于容量回收

    CacheBuilder.maximumSize(long):缓存将尝试回收最近没有使用或总体上很少使用的缓存项,除此之外,你还可以通过对缓存设定不同的权重,来决定它的回收顺序

3.4 刷新

通过前面的讲解,我们知道当大量线程用相同的key获取缓存值时,如果此时缓存过期了,那么只会有一个线程进入load方法,而其他线程则等待,直到缓存值被生成,这个听起来似乎是一种很危险的操作啊!不用担心,Guava还提供了另一种缓存策略,缓存值定时刷新:更新线程调用load方法更新该缓存,其他请求线程返回该缓存的旧值,这样对于某个key的缓存来说,只会有一个线程被阻塞 。这里就需要用到Guava cache的refreshAfterWrite方法。如下所示:

1.4.2.2 Read-Through

Read-Through 也是在查询操作中更新缓存,和 Cache-Aside 相比,唯一的区别就是,当缓存失效的时候(过期或LRU换出),Cache-Aside 是由业务代码负责把数据加载入缓存,而 Read-Through 则用缓存服务自己来加载,从而对业务代码是透明的。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值