MST

星途 面试题库

面试题:缓存设计之Caffeine基础使用

请阐述Caffeine缓存中如何设置缓存的过期策略,包括基于时间过期和基于访问频率过期,并给出相应的代码示例。
25.6万 热度难度
后端开发缓存设计

知识考点

AI 面试

面试题答案

一键面试

基于时间过期

Caffeine 支持两种基于时间的过期策略:写入后过期(expireAfterWrite)和访问后过期(expireAfterAccess)。

  1. 写入后过期(expireAfterWrite): 表示缓存项在被写入或更新后的指定时间后过期。
    import com.github.benmanes.caffeine.cache.Caffeine;
    import com.github.benmanes.caffeine.cache.LoadingCache;
    
    import java.util.concurrent.TimeUnit;
    
    public class CaffeineExample {
        public static void main(String[] args) {
            LoadingCache<String, String> cache = Caffeine.newBuilder()
                   .expireAfterWrite(5, TimeUnit.MINUTES)
                   .build(key -> "default value for " + key);
    
            cache.put("key1", "value1");
            // 在5分钟后,"key1" 对应的缓存项将过期
            String value = cache.get("key1");
            System.out.println(value);
        }
    }
    
  2. 访问后过期(expireAfterAccess): 表示缓存项在被访问(读或写)后的指定时间后过期。
    import com.github.benmanes.caffeine.cache.Caffeine;
    import com.github.benmanes.caffeine.cache.LoadingCache;
    
    import java.util.concurrent.TimeUnit;
    
    public class CaffeineExample2 {
        public static void main(String[] args) {
            LoadingCache<String, String> cache = Caffeine.newBuilder()
                   .expireAfterAccess(10, TimeUnit.SECONDS)
                   .build(key -> "default value for " + key);
    
            cache.put("key1", "value1");
            // 每次访问"key1",过期时间将重置,从最后一次访问开始10秒后过期
            String value = cache.get("key1");
            System.out.println(value);
        }
    }
    

基于访问频率过期

Caffeine 可以通过设置 eviction 策略来实现基于访问频率过期。eviction 策略可以通过 removalListener 来监听缓存项的移除事件,结合 accessOrder 来实现基于访问频率的过期。

import com.github.benmanes.caffeine.cache.Cache;
import com.github.benmanes.caffeine.cache.Caffeine;
import com.github.benmanes.caffeine.cache.RemovalCause;
import com.github.benmanes.caffeine.cache.RemovalListener;

import java.util.concurrent.TimeUnit;

public class CaffeineAccessFrequencyExample {
    public static void main(String[] args) {
        RemovalListener<String, String> removalListener = (key, value, cause) -> {
            if (cause == RemovalCause.EVICTED) {
                System.out.println("Evicted key: " + key + ", value: " + value);
            }
        };

        Cache<String, String> cache = Caffeine.newBuilder()
               .expireAfterWrite(1, TimeUnit.MINUTES)
               .maximumSize(100)
               .accessOrder(true)
               .removalListener(removalListener)
               .build();

        cache.put("key1", "value1");
        cache.put("key2", "value2");
        // 访问key1
        cache.getIfPresent("key1");
        // 当缓存达到最大容量100时,最少访问的项会被移除
    }
}

在上述代码中,accessOrder(true) 表示按照访问顺序(最不经常访问的优先被移除),结合 maximumSize 设置最大缓存项数量,当缓存达到最大数量时,最不经常访问的项会被移除。removalListener 用于监听缓存项的移除事件,这里主要关注因驱逐(RemovalCause.EVICTED)而移除的情况。