Caffeine Eviction策略

Caffeine缓存剔除策略有三个:

  • 基于容量剔除
  • 基于时间剔除
  • 基于引用剔除

基于容量剔除

// 如果缓存的条目大于maximumSize值时,caffeine将尝试剔除最近或很少使用的缓存条目
LoadingCache<Integer, String> caches = Caffeine.newBuilder()
                .maximumSize(2)
  							// 添加剔除缓存事件监听,cause就是剔除缓存的原因(参见RemovalCause枚举类)
                .removalListener(((key, value, cause) -> {
                    System.out.println(cause);
                }))
                .build(key -> key);

设置maximumSize值,如果缓存的条目大于maximumSize值时,caffeine将尝试剔除最近或很少使用的缓存条目。

LoadingCache<Integer, String> weightCaches = Caffeine.newBuilder()
                .maximumWeight(10)
                .weigher(((key, value) -> (Integer)key))
                .removalListener(((key, value, cause) -> {
                    System.out.println(cause);
                }))
                .build(key -> key + "val");

设置maximumWeight值,如果缓存条目的权重大于maximumWeight值时,caffeine将尝试剔除它。

PS: maximumSize和maximumWeight不能同时使用。

基于时间剔除

LoadingCache<Integer, String> accessCaches = Caffeine.newBuilder()
        .expireAfterAccess(10, TimeUnit.SECONDS)
        .removalListener(((key, value, cause) -> {
            System.out.println(cause);
        }))
        .build(key -> key + "val");

expireAfterAccess:自缓存条目最后一次读取或写入时开始,如果超过了该方法设定的时长,标记条目过期。

LoadingCache<Integer, String> writeCaches = Caffeine.newBuilder()
        .expireAfterWrite(10, TimeUnit.SECONDS)
        .removalListener(((key, value, cause) -> {
            System.out.println(cause);
        }))
        .build(key -> key + "val");

expireAfterWrite:自缓存条目创建或最后一次写入的时间点开始,如果超过了该方法设定的时长,标记条目过期。

LoadingCache<Key, Graph> graphs = Caffeine.newBuilder()
    .expireAfter(new Expiry<Key, Graph>() {
      public long expireAfterCreate(Key key, Graph graph, long currentTime) {
        // Use wall clock time, rather than nanotime, if from an external resource
        long seconds = graph.creationDate().plusHours(5)
            .minus(System.currentTimeMillis(), MILLIS)
            .toEpochSecond();
        return TimeUnit.SECONDS.toNanos(seconds);
      }
      public long expireAfterUpdate(Key key, Graph graph, 
          long currentTime, long currentDuration) {
        return currentDuration;
      }
      public long expireAfterRead(Key key, Graph graph,
          long currentTime, long currentDuration) {
        return currentDuration;
      }
    })
    .build(key -> createExpensiveGraph(key));

expireAfter(Expiry): 在可变持续时间过去之后标记条目过期。在条目的过期时间由外部资源决定的场景下使用比较理想。

基于引用的剔除

// 弱引用key和value
LoadingCache<Key, Graph> graphs = Caffeine.newBuilder()
    .weakKeys()
    .weakValues()
    .build(key -> createExpensiveGraph(key));
//软引用缓存值
LoadingCache<Key, Graph> graphs = Caffeine.newBuilder()
    .softValues()
    .build(key -> createExpensiveGraph(key));

Caffeine可以对key和value使用弱引用和软引用,这样缓存可以通过垃圾回收机制实现缓存条目的回收。
caffeine缓存条目剔除的入口方法BoundedLocalCache#maintenance()

@GuardedBy("evictionLock")
  void maintenance(@Nullable Runnable task) {
    lazySetDrainStatus(PROCESSING_TO_IDLE);

    try {
      drainReadBuffer();

      drainWriteBuffer();
      if (task != null) {
        task.run();
      }

      drainKeyReferences();// @1
      drainValueReferences();// @2

      expireEntries();// @3
      evictEntries(); // @4
    } finally {
      if ((drainStatus() != PROCESSING_TO_IDLE) || !casDrainStatus(PROCESSING_TO_IDLE, IDLE)) {
        lazySetDrainStatus(REQUIRED);
      }
    }
  }

代码@1:释放key弱引用队列。

代码@2:释放value弱引用/软引用队列。

代码@3:根据设置的超时时间,让缓存条目超时。

代码@4:删除标记了删除标记的条目。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值