求类似Guava LoadingCache但无并发支持的Java缓存库
嘿,刚好对这块挺熟悉的,给你几个完全适配单线程场景的选项——没有多余的并发控制开销,还能满足你要的延迟加载、缓存淘汰这些核心需求:
1. Caffeine 单线程模式(最贴近Guava体验)
Caffeine本来就是Guava Cache的继任者,性能还更优,而且它支持直接配置成单线程运行模式,彻底关掉并发相关的锁和线程池逻辑。用法和Guava的LoadingCache几乎一模一样,延迟加载、各种淘汰策略(LRU、LFU、过期策略)全都保留着。
只需要在构建时指定executor(Runnable::run),所有缓存操作就都会在当前线程执行,没有额外开销:
LoadingCache<String, Object> cache = Caffeine.newBuilder() .expireAfterAccess(10, TimeUnit.MINUTES) // 访问后过期的淘汰策略 .executor(Runnable::run) // 强制单线程执行 .build(key -> loadDataFromSource(key)); // 你的延迟加载逻辑
2. 手动实现轻量版LoadingCache(无依赖)
如果不想引入第三方库,自己基于LinkedHashMap写一个超轻量的版本也很简单。LinkedHashMap天然支持按访问顺序排序,刚好用来实现LRU淘汰,再加上延迟加载的逻辑就行——单线程下连synchronized都可以省掉,完全没有并发冗余代码:
public class SimpleSingleThreadCache<K, V> { private final LinkedHashMap<K, V> cacheStore; private final Function<K, V> valueLoader; // 初始化时指定最大容量和加载逻辑 public SimpleSingleThreadCache(int maxCapacity, Function<K, V> valueLoader) { this.valueLoader = valueLoader; // 第三个参数设为true,开启按访问顺序排序,实现LRU this.cacheStore = new LinkedHashMap<>(maxCapacity, 0.75f, true) { @Override protected boolean removeEldestEntry(Map.Entry<K, V> eldest) { return size() > maxCapacity; // 超过容量时移除最久未访问的条目 } }; } public V get(K key) { V value = cacheStore.get(key); if (value == null) { value = valueLoader.apply(key); cacheStore.put(key, value); } return value; } }
这个实现完全可控,代码量极少,刚好满足单线程场景的所有需求。
3. Apache Commons JCS 单线程配置
Apache Commons JCS虽然常被用于多线程/分布式场景,但也可以配置成纯单线程的本地缓存。你只需要在cache.ccf配置文件里关闭所有分布式、多线程相关的特性(比如设置isLateral=false、isRemote=false),再通过自定义CacheLoader实现延迟加载,就能得到一个轻量的单线程缓存,支持多种淘汰策略。
4. Ehcache 单线程本地缓存
Ehcache同样支持配置成单线程运行的本地缓存。在配置中关闭copyOnRead、copyOnWrite,不启用集群或多线程缓存模式,再利用它的CacheLoader机制实现延迟加载,就能满足需求。它的淘汰策略也很丰富,LRU、LFU、FIFO都能支持。
总结一下:如果想尽量贴近Guava LoadingCache的使用习惯,Caffeine的单线程模式是首选,API熟悉、性能好;如果不想加依赖,自己基于LinkedHashMap实现是最轻便的方案。
内容的提问来源于stack exchange,提问作者Nikola Mihajlović

