美文网首页
译 Guava Cache

译 Guava Cache

作者: lazyguy | 来源:发表于2019-05-30 15:13 被阅读0次

    源:https://github.com/google/guava/wiki/CachesExplained

    适用性


    缓存及其有用。blala

    Cache类似于一个ConcurrentMap,但并不完全一样。最基础的不同是ConcurrentMap保存所有的元素知道它们被明确删除。而Cache是会安排配置自动删除元素的以便于限制内存占用。在某些用例中,LoadingCache即便不使用它的删除功能,任然可以利用它的自动加载功能。

    加载数据


    使用CacheLoader加载

    LoadingCache是一个附加着CacheLoaderCache
    在创建LoadingCache的时候传入CacheLoader的实现,主要是实现V load(K key) throws Exception方法,既怎么去加载一个key的值。

    LoadingCache<Key, Graph> graphs = CacheBuilder.newBuilder()
           .maximumSize(1000)
           .build(
               new CacheLoader<Key, Graph>() {
                 public Graph load(Key key) throws AnyException {
                   return createExpensiveGraph(key);
                 }
               });
    
    ...
    try {
      return graphs.get(key);
    } catch (ExecutionException e) {
      throw new OtherException(e.getCause());
    }
    

    当我们通过get(K)去查询时,会返回已经被缓存的值,或者使用CacheLoader“原子性” 的加载一个新的值到缓存。因为load方法本身会抛异常,所以get方法也会抛对应的ExecutionException异常表示load失败。或者直接使用getUncheked(k)方法,所有异常都会被包裹成UncheckedException丢出。

    当使用loadAll加载大量key时,如果遇到key加载,loadAll是迭代去取值的,如果需要更有效率的取法,自己实现。

    使用Callable加载

    CacheLoader是创建Cache的时候的默认加载器,get(K,Callable<V>)则是get的时候单独传入一个针对本次调用的加载逻辑。

    Cache<Key, Value> cache = CacheBuilder.newBuilder()
        .maximumSize(1000)
        .build(); // look Ma, no CacheLoader
    ...
    try {
      // If the key wasn't in the "easy to compute" group, we need to
      // do things the hard way.
      cache.get(key, new Callable<Value>() {
        @Override
        public Value call() throws AnyException {
          return doThingsTheHardWay(key);
        }
      });
    } catch (ExecutionException e) {
      throw new OtherException(e.getCause());
    }
    
    直接手动插入

    cache.put(key, value)

    删除数据


    根据容量删除

    如果对Cache的大小在意。创建的时候配置CacheBuilder.maxmumSize(long)配置缓存大小。
    "接近容量"大小的时候会自动删除元素。元素也可以有Weight比重,但注意是在元素创建的时候计算出来静态放置的。后面不会改变。

    LoadingCache<Key, Graph> graphs = CacheBuilder.newBuilder()
           .maximumWeight(100000)
           .weigher(new Weigher<Key, Graph>() {
              public int weigh(Key k, Graph g) {
                return g.vertices().size();
              }
            })
           .build(
               new CacheLoader<Key, Graph>() {
                 public Graph load(Key key) { // no checked exception
                   return createExpensiveGraph(key);
                 }
               });
    
    根据时间删除

    2种策略,见名知意:
    expireAfterAccess(long, TimeUnit)
    expireAfterWrite(long, TimeUnit)
    guava提供测试工具模拟时间流逝TickerCacheBuilder.ticker(Ticker)

    根据引用删除

    最好使用配置明显的Cache size去解决内存大小,用折后在哪个策略,是依赖于JVM,而且会导致缓存使用==去代替'compare`在内部逻辑中的比较。因为jvm的判断是基于引用的。

    手动删除

    Cache.invalidate(key)
    Cache.invalidateAll(keys)
    Cache.invalidateAll()

    删除的时候得到通知Removal Listeners

    不要进行耗性能和超时的动作,如果需要,考虑RemovalListeners.asynchronous(RemovalListener,Executor)包裹。

    删除数据的时候到底发生了什么?

    延迟删除,只在读和写的时候才真正去做删除维护,所以remove listener才不能过长,因为是同步执行的,会阻塞对应的操作。需要频繁删除维护,需要用户自己去调用cleanUp().

    刷新数据


    LoadingCahe.refresh(K) 异步调用底层的CacheLoader.reload(K,V)刷新值。如果异常,保留原来的值,只打印日志。
    自动定时刷新可以在CacheBuilder中配置CacheBuilder.refreshAfterWrite(long,TimeUnit).
    值得注意的是refreshAfterWrite仅仅只在到时后,标记某个key可以被更新了,只有在查询来临的时候才会真正触发更新。在同时有定时过期和定时更新的Cache上,只有在标记的key在更新时间到后,查询没有来临,更新未触发。才会被过期策略考虑入删除。

    注意Guava提供的demo,CacheLoader.reload的实现不仅可以判断哪些可以key应该被更新,而且是异步的。

    // Some keys don't need refreshing, and we want refreshes to be done asynchronously.
    LoadingCache<Key, Graph> graphs = CacheBuilder.newBuilder()
           .maximumSize(1000)
           .refreshAfterWrite(1, TimeUnit.MINUTES)
           .build(
               new CacheLoader<Key, Graph>() {
                 public Graph load(Key key) { // no checked exception
                   return getGraphFromDatabase(key);
                 }
    
                 public ListenableFuture<Graph> reload(final Key key, Graph prevGraph) {
                   if (neverNeedsRefresh(key)) {
                     return Futures.immediateFuture(prevGraph);
                   } else {
                     // asynchronous!
                     ListenableFutureTask<Graph> task = ListenableFutureTask.create(new Callable<Graph>() {
                       public Graph call() {
                         return getGraphFromDatabase(key);
                       }
                     });
                     executor.execute(task);
                     return task;
                   }
                 }
               });
    

    统计功能


    CacheBuilder.recordStats 开启缓存的辅助统计功能。
    Cache.stats方法可以返回一个CacheStats对象,包含很多统计信息。

    相关文章

      网友评论

          本文标题:译 Guava Cache

          本文链接:https://www.haomeiwen.com/subject/uixmtctx.html