CacheBuilder 构建缓存

CacheBuilder

中文官方教程
Github

Guava Cache与ConcurrentMap很相似,但也不完全一样。最基本的区别是ConcurrentMap会一直保存所有添加的元素,
直到显式地移除。相对地,Guava Cache为了限制内存占用,通常都设定为自动回收元素。在某些场景下,尽管LoadingCache 不回收元素,它也是很有用的,因为它会自动加载缓存。
通常来说,Guava Cache适用于:
你愿意消耗一些内存空间来提升速度。
你预料到某些键会被查询一次以上。
缓存中存放的数据总量不会超出内存容量。(Guava Cache是单个应用运行时的本地缓存。它不把数据存放到文件或外部服务器。如果这不符合你的需求,请尝试Memcached这类工具)
如果你的场景符合上述的每一条,Guava Cache就适合你。
————————摘自中文教程

构建一个Cache

 Cache<Object, Object> cache = CacheBuilder.newBuilder()
 				//	容量大小
                .maximumSize(4)
                // 设置内部哈希表的大小
                .initialCapacity(16)
                // 并发数
                .concurrencyLevel(4)
                // 开启统计功能
                .recordStats()
                // 设置一个remove监听器
                .removalListener(new RemovalListener<Object, Object>() {
     

                    @Override
                    public void onRemoval(RemovalNotification<Object, Object> notification) {
     
                        // TODO 
                    }
                })
                // 定时回收
                .expireAfterAccess(30, TimeUnit.MINUTES)
                .build();

缓存回收

guava cache提供三种回收方式:容量回收,定时回收,引用回收

容量回收

  1. CacheBuilder通过 CacheBuilder .maximumSize(long size)来 设置缓存大小,超过则缓存将尝试回收最近没有使用或总体上很少使用的缓存项。CHOUT

  2. 权重函数
    CacheBuilder通过 CacheBuilder .weigher(Weigher weigher)来设置权重函数,

@GwtCompatible
@FunctionalInterface
public interface Weigher<K, V> {
     
//返回缓存项的权重。参赛重量没有单位;而是简单地相对于彼此。
 int weigh(K key, V value);
}

CacheBuilder .maximumWeight(long weight)来设置最大总重,并且不能和maximumSize一起使用
cache是如何计算丢弃的:
最大总重会平分到每个Segment,例如总重100,有4个Segment,那每个Segment的重量为25,put数据,如果权重函数的返回值超过该Segment的权重则丢弃该值。

@Test
   public void weigherTest() {
     
       Cache<Object, Object> cache = CacheBuilder.newBuilder()
               .weigher(new Weigher<Object, Object>() {
     

                   @Override
                   public int weigh(Object key, Object value) {
     
                   	//  根据value的长度计算
                       return value.toString().length();
                   }
               }).maximumWeight(100).build();
       	cache.put("A", "AAAAA"); //Segments[1] 5
       	cache.put("B", "BBBBBBBBBB");//Segments[1] 10
       	cache.put("C", "CCCCCCCCCCCCCCC"); // Segments[3] 15
        cache.put("D", "DDDDDDDDDDDDDDDDDDDD");//Segments[3] 20
        cache.put("E", "EEEEEEEEEEEEEEEEEEEEEEEEE");//Segments[3] 25
        cache.put("F", "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFF");//Segments[2] 30
        cache.asMap().forEach((x,y)->{
     
            System.out.println(y.toString().length()+"\t"+ y);
        });
   }

输出结果:
25 EEEEEEEEEEEEEEEEEEEEEEEEE
5 AAAAA
10 BBBBBBBBBB
原因:
1, 由于A、B在同一个Segment并且value的长度和没有超过25,所有没有丢弃。
2,C、D、E在同一个Segment,value的和超过25,所以会丢弃前面的C、D,保留了E
3,F在下标为2的Segment里面,value长度超过25,直接丢弃

定时回收

CacheBuilder提供两种定时回收的方法:

  1. expireAfterAccess(long, TimeUnit):缓存项在给定时间内没有被读/写访问,则回收。请注意这种缓存的回收顺序和基于大小回收一样。
  2. expireAfterWrite(long, TimeUnit):缓存项在给定时间内没有被写访问(创建或覆盖),则回收。如果认为缓存数据总是在固定时候后变得陈旧不可用,这种回收方式是可取的。

引用回收

  1. CacheBuilder.weakKeys():使用弱引用存储键。当键没有其它(强或软)引用时,缓存项可以被垃圾回收。因为垃圾回收仅依赖恒等式(= =),使用弱引用键的缓存用==而不是equals比较键。
  2. CacheBuilder.weakValues():使用弱引用存储值。当值没有其它(强或软)引用时,缓存项可以被垃圾回收。因为垃圾回收仅依赖恒等式(= =),使用弱引用值的缓存用==而不是equals比较值。
  3. CacheBuilder.softValues():使用软引用存储值。软引用只有在响应内存需要时,才按照全局最近最少使用的顺序回收。考虑到使用软引用的性能影响,我们通常建议使用更有性能预测性的缓存大小限定(见上文,基于容量回收)。使用软引用值的缓存同样用==而不是equals比较值。

CacheStats

CacheBuilder通过CacheBuilder.recordStats()开启统计功能;
CacheStats 源码

public final class CacheStats {
     
  // 命中次数
  private final long hitCount;
  // miss次数
  private final long missCount;
  // 添加成功次数
  private final long loadSuccessCount;
  // 添加失败次数
  private final long loadExceptionCount;
  // 总负载时间
  private final long totalLoadTime;
  // 驱逐统计
  private final long evictionCount;
 .......

通过CacheStats.hitRate()方法获取命中率,计算方式:hitCount /(hitCount+missCount)
missRate()方法与此类似,计算方式:missCount /(hitCount+missCount)

你可能感兴趣的:(guava,java)