• Guava Cache


    内容摘要

    • 写入数据到缓存
      • 手动写入 (put)
      • 自动加载(按需加载)
    • 数据清理
      • 过期、清理
        • 基于容量的清理触发条件
        • 基于时间的过期方案
        • 基于Reference Key,Value
        • 手动移除 (显式移除)
      • RemoveListener
      • 数据清理时机
    • refresh
    • 配置说明
    • 场景说明

    1、写数据到缓存

    1.1 手动写入 put

    Guava Cache 底层是由一个ConcurrentMap实现的,那么底层必然支持两个常规的put:put(k,v), putIfAbsent(k,v)。

    从类图上来看,基于Guava Cache实现的cache必然是有一个put(k,v)方法的,直接放k,v对到cache中,并替换掉原有的数据。从接口Cache 来看,只提供了一个put(k,v)方法,底层是一个ConcurrentMap,那么putIfAbsent(k,v)的特性好像被丢弃了。如果你希望使用putIfAbsent,那么可以调用Cache.asMap().putIfAbsent(k,v)。

    1.2 自动加载(按需加载)

    除了上面的put直接写入cache方式外,Guava Cache还提供了两种实现了get-if-absent-compute语义的方式。

    所谓的get-if-absent-compute语义是说:在调用get方法时,如果发现指定的值不存在,则通过加载、计算等方式来提供值。也可以将这个语义理解为lazy load(懒加载、按需加载)。

    这两种方式分别为:Cache.get(key, Callable) 、LoadingCache。

    Cache.get(key, Callable) 在调用get时,指定一个Callable,如果值不存在时,调用Callable来计算值。计算到值后放入Cache中,并返回结果。

    LoadingCache 必须有一个CacheLoader配合一起使用,LoadingCache与CacheLoader的几个方法的调用关系:

    LoadingCache.get(k) ->  CacheLoader.load(k)

    LoadingCache.refresh(k) ->   CacheLoader.reload(k)

    LoadingCache.getAll(keys) -> CacheLoader.loadAll(keys)

    CacheLoader是不保证一定可以加载成功,所以它的所有方法都是有异常的。

    2、数据清理

    任何一种Cache都必须支持一定的Cache清理策略,不然数据会一直增长,内存肯定是扛不住的。Guava Cache也提供了多种Cache清理策略:

    2.1 过期、清理

    Guava Cache采用基于容量、Soft引用、Weak引用的清理触发条件,基于过期时间、权重来决定哪些数据优先清理,采用LRU算法来清理数据。

    2.1.1 基于容量的清理触发条件

    如果你的cache数量不应该一直保持增长状态,你需要设定总量来限定cache的容量。可以通过CacheBuilder.maximumSize(long capacity)来限定。当容量即将达到上限时,会自动的进行数据清理。默认的最大容量是 1<<30,如果想要限定,只能设置比1<<30小的数。

           因为Guava Cache有默认容量,也就是最大容量的限制,所以任何一个Guava Cache都是有界cache,不会无限制的增加。

           在快要达到容量限定值开始清理数据时,采用的是LRU清理算法。与此同时,还可以根据每一个key-value的weight来控制清理,一个key-value的weight越低越容易被清除掉。默认情况下,每一个key-value的weight都是一样的,即为1。当然了你可以自定义weight算法,通过CacheBuilder.weight(weight)即可。

    其实严格来讲,这个并不属于

    2.1.2 基于时间的过期方案

    Guava Cache提供了两种基于时间的数据过期方案:

    1)     expireAfterWrite()

    2)     expireAfterAccess()

    根据访问后的时间来控制数据是否过期。需要注意的是,设置了基于时间后,不会在内部另外启动线程来定时清理掉过期的数据的。是依赖的与get请求,也就是说每一次访问一个key时,会记录时间,再一次访问时,会先判断数据是否过期了,一旦过期了,就清理掉,被清理掉后,下一次访问时,会调用配置的CacheLoader进行加载。

    当使用基于时间的过期策略时,可以自定义自己的计时器的,使用CacheBuilder.ticker(ticker)即可。

    需要说明的是,这里的基于时间的过期策略是针对每一个key-value的,如果你的业务中极有可能每一个key-value都不一样的话,就不适合使用了。如果你对业务中有可以枚举的几个时间过期粒度,可以创建多个Guava Cache来完成的。

    2.1.3 基于Reference的Key、Value

    可以利用weak reference, soft reference来清理缓存。具体来说 weak reference 可以用在key, value上;soft reference 可以用在 value上。

     2.1.4 手动移除(显示移除)

    当然了,Guava Cache也提供了最基本的手动移除key-value的方案,直接从cache移除:

    Cache.invalidate(key) 单个移除

    Cache.invalidateAll(keys) 批量移除

    Cache.invalidate() 移除所有

     2.2 RemoveListener

    如果你的业务对数据的清理感兴趣,还可以指定RemoveListener的。

     2.3 数据清理时机

    从上面的几种清理策略或者过期策略来看,Guava Cache 提供的是被动清理方案,不论是基于容量、基于时间、基于Reference,它们都是被动的清理方案。而手动清理方案虽然是一种主动的清理方案,但它只是针对与你已经确定了不会再用的数据。

           Cache.cleanUp() 是一种主动的清理方案,它会清理掉过期的数据。

    3、refresh

    LoadingCache中的refresh 提供了值替换的功能。在调用refresh时,会先调加载新值,新值加载到后替换掉老值,并返回老值。如果加载不到新值,老值是被保留的,不会被替换掉的。

    LoadingCache是引发CacheLoader调用reload方法的,CacheLoader的reload返回的是ListenableFuture,也就表明了,支持同步reload,也支持异步的reload的。

    4、配置说明

    Guava Cache中的两种cache(Cache,LoadingCache)的实现分别由LocalManuelCache、LocalLoadingCache来完成。创建这两种cache也很简单,使用CacheBuilder即可。在构建cache时,需要配置数据清理策略、并发级别等。

    concurrencyLevel:底层的LocalCache 也是一个ConcurrentMap,它的实现与JDK8之前版本中的ConcurrentHashMap类似,也采用了多个segment来提高并发。他们都可以配置concurrencyLevel,来控制segment的数量,来提高并发。ConcurrentHashMap的默认值是16,最大值是1<<16;这里的默认值是4,最大值为 1<<16。

    initialCapacity:初始容量配置,默认值是16.

    maximumSize:最大容量。

    maximumWeight:最大权重

    keyEquivalence、valueEquivalence,用于指定内部判断key,value时,是否一样的算法。另外需要说明的是,默认情况下Guava Cache内部判断key, value是否相等时,针对不同的配置采用不同的方案的。如果启用了weakKey,weakValue,softValue的情况下,相应的key或者value的相等性判断是采用的是 ==,如果没有启用weakKey,softValue,weakValue的情况下,相应的key,value的相等性判断使用是equals()。

    5、场景说明

    不适用于数据有不同的过期时间的场景。

  • 相关阅读:
    EF架构~简洁关联表插入,优越的代码性能!
    基础才是重中之重~你是否真正了解TransactionScope?
    基础才是重中之重~如何整理BLL与DAL层的文件
    java Byte 和byte 差别及byte[ ]和string转换
    转: java的InputStream和OutputStream的理解
    java.awt.list java.util.list 区别
    java.util.Scanner 总结
    java .io OutputStream 与InputStream
    java 3中方法复制一个文件
    网络爬虫 简介
  • 原文地址:https://www.cnblogs.com/f1194361820/p/10998979.html
Copyright © 2020-2023  润新知