Java中的Caffeine加载与驱逐策略详解
作者:蜡笔小久
这篇文章主要介绍了Java中的Caffeine加载与驱逐策略详解,Caffeine是基于Java 8的高性能缓存库,可提供接近最佳的命中率,Caffeine与ConcurrentMap相应,但是不完全相同,本文主要介绍Caffeine,需要的朋友可以参考下
一、Caffiene 简介
Caffeine是基于Java 8的高性能缓存库,可提供接近最佳的命中率。
Caffeine与ConcurrentMap相应,但是不完全相同。最根本的区别是ConcurrentMap会保留所有添加到其中的元素,知道将其明确删除为止. Cache另一方面,通常将A配置为自动删除元素,以限制其内存占用量。在某些情况下,LoadingCache或AsyncLoadingCache可能很有用,即使它没有删除条目, 因为它能够自动加载缓存信息。
二 、Caffeine四种加载策略
1.手动加载缓存信息
Cache<String, Integer> cache = Caffeine.newBuilder() // 写入缓存后30分钟后过期 .expireAfterWrite(30, TimeUnit.MINUTES) // 最大缓存数量1000 .maximumSize(1000) .build(); String key = "1"; // 新增缓存 cache.put(key, 1); cache.put("2", 2); cache.put("3", 3); // 从缓存中获取数据: 如果存在在返回"1"的值,如果不存在返回null System.out.println(cache.getIfPresent(key)); // 缓存key不存在cache中, 则新增一条数据到cache中 String key1 = "4"; cache.get(key1, k -> 3); System.out.println(cache.getIfPresent(key1)); // 从cache中移除缓存 cache.invalidate("1");
2.LoadingCache
public void loadingCache() { LoadingCache<String, Integer> loadingCache = Caffeine.newBuilder() // 写入缓存后30分钟后过期 .expireAfterWrite(30, TimeUnit.MINUTES) // 最大缓存数量1000 .maximumSize(1000) // build中的CacheLoader可以在初始化LoaddingCache时,加载一部分数据到内存中, // 此处就把key的hash值作为value .build(this::getIntByKey); Integer val = loadingCache.get("1", this::getIntByKey); System.out.println(val); // 批量获取键值 Map<String, Integer> all = loadingCache.getAll(Arrays.asList("1", "2")); System.out.println(JSON.toJSONString(all.values())); } public Integer getIntByKey(String key) { return key.hashCode(); }
3.异步手动加载
public void sync() { AsyncCache<String, Integer> asyncCache = Caffeine.newBuilder() // 写入缓存后30分钟后过期 .expireAfterWrite(30, TimeUnit.MINUTES) // 最大缓存数量1000 .maximumSize(1000) .buildAsync(); // 如果Key不存在, 则把key和value 加入到cache中, CompletableFuture提供了一个阻塞Cache, 直到异步完成 CompletableFuture<Integer> future = asyncCache.get("1", this::getIntByKey); } public Integer getIntByKey(String key) { return key.hashCode(); }
4.异步加载
public void syncLoadingCache() { AsyncLoadingCache<String, Integer> async = Caffeine.newBuilder().buildAsync(new AsyncCacheLoader<>() { @Override public @NonNull CompletableFuture<Integer> asyncLoad(@NonNull String key, @NonNull Executor executor) { return new CompletableFuture<>(); } }); CompletableFuture<Integer> future = async.get("1"); CompletableFuture<Map<String, Integer>> all = async.getAll(Arrays.asList("1", "2")); }
三、CleanUp
由于Caffeine 不会再值过期后立即执行清除,而是在写入或者读取操作之后执行少量维护工作,或者在写入读取很少的情况下,偶尔执行清除操作。如果我们项目写入或者读取频率很高,那么不用担心。如果想入写入和读取操作频率较低,那么我们可以通过Cache.cleanUp() 加scheduler 去定时执行清除操作。
Scheduler可以迅速删除过期的元素,***Java 9 +***后的版本,可以通过Scheduler.systemScheduler(), 调用系统 线程,达到定期清除的目的
代码实现:
Cache<String, Integer> graphs = Caffeine.newBuilder() // 设置一个定时器任务 .scheduler(Scheduler.systemScheduler()) // 添加一个移除元素监听事件 .removalListener((k , v, cause) -> { System.out.println(k); System.out.println(v); System.out.println(cause.wasEvicted()); }) .expireAfterWrite(3, TimeUnit.SECONDS) .weakValues() .build(); // 创建一个清理线程 Cleaner cleaner = Cleaner.create(); // 注册一个对象,并在对象运行时执行一个cleanUp操作 cleaner.register("1", graphs::cleanUp); graphs.put("1", 1); graphs.put("2", 2); graphs.put("3", 3); Thread.sleep(5000); graphs.put("3", 3); System.out.println(graphs.getIfPresent("1")); System.out.println(graphs.getIfPresent("2")); System.out.println(graphs.getIfPresent("3"));
到此这篇关于Java中的Caffeine加载与驱逐策略详解的文章就介绍到这了,更多相关Caffeine加载与驱逐策略内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!