常见问题
固定条目
固定条目是无法通过驱逐策略删除的条目。 当条目是一个有状态的资源(如锁)时,这是非常有用的,只有在客户端完成使用后才能将其丢弃。 在这些情况下,驱逐一个条目并重新计算它的行为会导致资源泄漏。
通过使权重和评估条目的权重为0,可以从最大size驱逐中排除条目。 然后成员不计入整体容量,并被最大size驱逐跳过。 必须定义自定义Weigher,用于评估条目是否被固定。
一个条目可以通过使用Long.MAX_VALUE的持续时间(大约300年)来排除。 自定义Expiry必须定义,用于评估条目是否固定。
将条目写入高速缓存时评估权重和到期时间。 这可以通过使用cache.asMap().compute来实现绑定pin和unpin。
递归计算
在原子操作内执行的加载,计算或回调可能不会写入缓存。 ConcurrentHashMap不允许这些递归写操作,并可能导致livelock(Java 8)或IllegalStateException(Java 9)。
解决方法是异步执行计算,例如使用AsyncLoadingCache。 在这种情况下映射已经建立,值是一个CompletableFuture,并且计算在缓存的原子范围之外执行。 如果发生无序的依赖链,这可能仍会发生死锁。
写竞争
Caffeine可能发生竞争的情况是,当前正在计算的条目的数量与高速缓存曾经包含的最大条目数量相似或者大于该条目的最大数量。这对应于当前计算条目接近底层ConcurrentHashMap的总容量,这阻止了调整map大小,直到加载函数完成。
缓存正在预热时(虽然可能根本没有)可能会发生。正在进行的计算的数量与缓存的容量相似的情况在小型缓存中可能更为明显。如果您观察到由于此类问题而导致的竞争(显示为在不同的请求阻塞在ConcurrentHashMap中的同一个锁上),请考虑将初始容量增加到预期的最大并发量以补偿,或使用异步缓存。
ConcurrentHashMap的内部文档中描述了一个很好的经验法则, 两个线程访问不同元素的锁争用概率在随机哈希下约为1 /(8 *元素)。