Caffeine 结合了调度程序和执行程序服务

问题描述 投票:0回答:1

我在以下配置中使用咖啡因:

    Cache<String, String> cache = Caffeine.newBuilder()
                .executor(newWorkStealingPool(15))
                .scheduler(createScheduler())
                .expireAfterWrite(10, TimeUnit.SECONDS)
                .maximumSize(MAXIMUM_CACHE_SIZE)
                .removalListener(this::onRemoval)
                .build();


    private Scheduler createScheduler() {
        return forScheduledExecutorService(newSingleThreadScheduledExecutor());
    }

我是否正确地假设

onRemoval
方法将在
newWorkStealingPool(15)
ForkJoinPool 上执行,并且只会调用调度程序来查找需要驱逐的过期条目?

意味着事情会是这样的:

  1. 调用单线程调度程序(每〜1秒)
  2. 找到所有要驱逐的过期条目
  3. 对缓存生成器中定义的
    newWorkStealingPool(15)
    中的每个被逐出的条目执行 onRemoval?

我没有找到解释此行为的文档,所以我在这里询问

Tnx

java caching java-8 caffeine-cache
1个回答
5
投票

您的假设很接近,只是在实践中稍微优化了一些。

  1. 缓存读取和写入在底层哈希表上执行,并附加到内部环形缓冲区。
  2. 当缓冲区达到阈值时,任务将提交给
    Caffeine.executor
    来调用
    Cache.cleanUp
  3. 当此维护周期运行时(在锁定状态下),
    • 缓冲区被耗尽,事件根据逐出策略重放(例如 LRU 重新排序)
    • 任何可驱逐条目都将被丢弃,并将任务提交给
      Caffeine.executor
      来调用
      RemovalListener.onRemoval
    • 下一个条目到期之前的持续时间是计算并提交给调度程序的。这是由 pacer 保护的,因此通过确保计划任务之间发生约 1 秒来避免过度调度。
  4. 当调度程序运行时,任务会提交给
    Caffeine.executor
    以调用
    Cache.cleanUp
    (请参阅 #3)。

调度程序执行最少量的工作,任何处理都会推迟到执行程序。由于使用 O(1) 算法,维护工作很便宜,因此根据使用活动,维护工作可能经常发生。它针对小批量工作进行了优化,因此计划调用之间强制执行约 1 秒的延迟有助于每次调用捕获更多工作。如果下一个过期事件发生在遥远的将来,那么调度程序在此之前不会运行,尽管调用线程可能会由于其在缓存上的活动而触发维护周期(请参阅#1,2)。

© www.soinside.com 2019 - 2024. All rights reserved.