17

私は:LoadingCache<K,V>を使用して作成しましたCacheBuilder

LoadingCache<K,V> myCache = CacheBuilder.newBuilder()
    .expireAfterAccess(1, TimeUnit.MINUTES)
    .maximumSize(500)
    .build(someCacheLoader);

キャッシュ内のすべてのエントリ(キーと値)を定期的に繰り返す必要があります。私は、、LoadingCache#asMap()および次のいずれかを使用してそれを達成できることを知っています。

前者の場合:

for (Map.Entry<K, V> entry : myCache.asMap().entrySet()) {
    K key = entry.getKey();
    V value = entry.getValue();

    doSomeWorkOn(key, value);
}

これにより、キャッシュ内のすべてのエントリのアクセス時間が更新されますか?私はJavaDocをCacheBuilder#expireAfterAccess(long, TimeUnit)かなり詳しく読んでいますが、この場合はあいまい/不明確であることがわかりました。

エントリの作成、その値の最新の置換、または最後のアクセスから一定の期間が経過すると、各エントリがキャッシュから自動的に削除されることを指定します。アクセス時間は、すべてのキャッシュ読み取りおよび書き込み操作(Cache.asMap().get(Object)およびを含むCache.asMap().put(K, V))によってリセットされますが、のコレクションビューに対する操作によってはリセットされませんCache.asMap

明らかに、私が言及した2番目の反復方法ではアクセス時間リセットされますが、最初の方法でどのような動作が使用されているかを知りたいと思います。

4

1 に答える 1

15

私はこれを解釈します:

(...)ただし、Cache.asMapのコレクションビューに対する操作ではありません

entrySet、、、keySetおよびを参照しvaluesます。これらは、の3つのコレクションビューですMap。したがって、それらを利用してもアクセスが発生することはありません。

それぞれの場合の動作を示すJUnit(+ Mockito)テストを次に示します。entrySetまたはを介して値を読み取ると、エントリが削除されるのを防ぐことはできvaluesませentrySet(またはからキーを読み取ることもできませんkeySet)。ドキュメントで指定されているように、を使用asMap().get()して読み取ることはアクセスとしてカウントされます。

設定

private Ticker ticker = Mockito.mock(Ticker.class);

@SuppressWarnings({"unchecked"})
private RemovalListener<String, String> removalListener = Mockito.mock(RemovalListener.class);

private Cache<String, String> cache = CacheBuilder.newBuilder()
            .expireAfterAccess(5, TimeUnit.SECONDS)
            .removalListener(removalListener)
            .ticker(ticker)
            .build();

entrySet

@Test
public void testEntrySetAccessDoesNotCountAsAccess() {
    //write
    when(ticker.read()).thenReturn(TimeUnit.SECONDS.toNanos(0));
    cache.put("foo", "bar");

    //read
    when(ticker.read()).thenReturn(TimeUnit.SECONDS.toNanos(4));
    cache.asMap().entrySet().iterator().next().getValue();
    cache.asMap().entrySet().iterator().next().getKey();

    //maintenance
    when(ticker.read()).thenReturn(TimeUnit.SECONDS.toNanos(6));
    cache.cleanUp();

    verify(removalListener).onRemoval(Mockito.<RemovalNotification<String,String>>any());
}

keySet

@Test
public void testKeySetAccessDoesNotCountAsAccess() {
    //write
    when(ticker.read()).thenReturn(TimeUnit.SECONDS.toNanos(0));
    cache.put("foo", "bar");

    //read
    when(ticker.read()).thenReturn(TimeUnit.SECONDS.toNanos(4));
    cache.asMap().keySet().iterator().next();

    //maintenance
    when(ticker.read()).thenReturn(TimeUnit.SECONDS.toNanos(6));
    cache.cleanUp();

    verify(removalListener).onRemoval(Mockito.<RemovalNotification<String,String>>any());
}

values

@Test
public void testValuesAccessDoesNotCountAsAccess() {
    //write
    when(ticker.read()).thenReturn(TimeUnit.SECONDS.toNanos(0));
    cache.put("foo", "bar");

    //read
    when(ticker.read()).thenReturn(TimeUnit.SECONDS.toNanos(4));
    cache.asMap().values().iterator().next();

    //maintenance
    when(ticker.read()).thenReturn(TimeUnit.SECONDS.toNanos(6));
    cache.cleanUp();

    verify(removalListener).onRemoval(Mockito.<RemovalNotification<String,String>>any());
}

asMap().get()

@Test
public void testMapGetAccessCountsAsAccess() {
    //write
    when(ticker.read()).thenReturn(TimeUnit.SECONDS.toNanos(0));
    cache.put("foo", "bar");

    //read
    when(ticker.read()).thenReturn(TimeUnit.SECONDS.toNanos(4));
    cache.asMap().get("foo");

    //maintenance
    when(ticker.read()).thenReturn(TimeUnit.SECONDS.toNanos(6));
    cache.cleanUp();

    verify(removalListener, never()).onRemoval(Mockito.<RemovalNotification<String,String>>any());
}
于 2013-01-17T04:15:26.400 に答える