如何使用咖啡因getAll()?



标题非常简单,我试图使用咖啡因缓存我的Minecraft插件,我似乎找不到cache.getAll()的任何好例子。文档也没有帮助。我只看到<,>?。我真的认为文档应该提供示例。所以我想问的是是否有人可以提供一个例子

实际上使用文档,您应该能够理解它期望作为参数的内容。作者写得很好。如果你不知道,我建议你阅读Java泛型并理解语法。

TL;博士:

Cache<String, Integer> cache = Caffeine.newBuilder().build();
cache.getAll(List.of("one", "two", "three"), keys -> {
Map<String, Integer> result = new HashMap<>();
keys.forEach(key -> {
if (key.equals("one")) result.put(key, 1);
else if (key.equals("two")) result.put(key, 2);
else if (key.equals("three")) result.put(key, 3);
});
return result;
});

这个例子可能在功能方面没有多大意义,但它是一个例子。

长版本

文档有一个方法签名:

MapgetAll (Iterable, ?扩展Map

让我们来分析一下。

MapgetAll

getAll方法返回一个键类型为K,值类型为V的Map。如果你的缓存实现是这样的:

Cache<String, Integer> cache = Caffeine.newBuilder().build();

thenK == StringandV == Integer

方法的第一个参数是:

Iterable

现在Iterable是一个JDK接口,几乎所有的集合都实现了它。检查"已知"字样。实现类。问号实际上表示"任何扩展了K的类型"。(其中K在示例中为String)

作为第一个参数,我们可以这样使用:

List.of("one", "two")

Function, ?扩展Map

这可能看起来令人困惑,但如果你试图再次分解它,它就不会。Function是一个接口(它只声明一个方法,因此是函数式的),它声明第一个类型是输入的类型,第二个类型是返回的类型。更多信息在这里。

因此,? super Set<? extends K>Set的超集,其元素类型为K(在本例中称为String)。为什么作者选择了super关键字?谷歌一下"PECS"是什么(生产者扩展,消费者超级)。

然后​? extends Map<? extends K,​? extends V>Map的实现,键类型为K,值类型为V(或Integer)。

指出

返回与键关联的值的映射,必要时创建或检索这些值。返回的映射包含已经缓存的条目,以及新加载的条目;它永远不会包含空键或空值。

不言自明,但请注意,返回的映射将包含所有缓存值和mappingFunction的结果组合-没有null的键/值

对缓存中未存在的所有键执行一次对mappingFunction的请求

您的mappingFunction将只被调用一次,并带有所有被请求但在缓存中未找到的键的列表。

mappingFunction返回的所有表项都将存储在缓存中,覆盖之前缓存的值

不言自明,mappingFunction返回的映射将替换或存储在缓存

用户指南提供了该功能的一个简单示例。getAll方法在所有类型的缓存中都可用。

同步缓存

在这个抽象中,调用者将阻塞等待加载完成

Cache<Key, Graph> cache = Caffeine.newBuilder().build();
cache.put(k1, v1);
// Loads k2 & k3 (uses k1)
Map<Key, Graph> graphs = cache.getAll(Set.of(k1, k2, k3),
keys -> createExpensiveGraphs(keys));

如果您希望将调用者与加载函数解耦,则创建LoadingCache。如果提供的CacheLoader没有实现批量功能,那么它将退回到逐个加载。

LoadingCache<Key, Graph> cache = Caffeine.newBuilder()
.build(CacheLoader.bulk(keys -> createExpensiveGraphs(keys)));
Map<Key, Graph> graphs = cache.getAll(keys);

注意,在这个抽象中,负载是非阻塞的。如果getAll正在检索k2,并且阻塞get(k2)同时发生,则两个负载都将在飞行中。当getAll完成时,它将覆盖现有的值。这种行为是因为我们不能在ConcurrentHashMap计算方法中锁定多个条目,但是如果使用AsyncCache,这个问题就解决了。

异步缓存

在这个抽象中,缓存存储到CompletableFuture的映射并将其返回给调用者。你可以使用封装为异步的同步函数来调用,也可以使用直接返回期货的异步函数来调用。

AsyncCache<Key, Graph> cache = Caffeine.newBuilder().buildAsync();
CompletableFuture<Map<Key, Graph>> graphs1 = cache.getAll(Set.of(k1, k2, k3),
keys -> createExpensiveGraphs(keys));
CompletableFuture<Map<Key, Graph>> graphs2 = cache.getAll(Set.of(k1, k2, k3),
(keys, executor) -> createExpensiveGraphFutures(keys));

加载逻辑可以使用AsyncLoadingCache对调用者隐藏。

AsyncLoadingCache<Key, Graph> cache = Caffeine.newBuilder()
.build(AsyncCacheLoader.bulk(keys -> createExpensiveGraphs(keys)));
CompletableFuture<Map<Key, Graph>> graphs = cache.getAll(keys);

在这个抽象中,getAll将阻止后续对同一键的get调用。这是由于底层映射持有一个正在运行的未来条目,因此在批量操作完成时插入占位符并完成占位符。

最新更新