5

私はこのようなローディングキャッシュを持っています:

MyCacheLoader loader=new MyCacheLoader();
MyRemovalListener listener=new MyRemovalListener();
LoadingCache<String, String> myCache = CacheBuilder.newBuilder()
                .concurrencyLevel(10)
                .weakKeys()
                .maximumSize(2)
                .expireAfterWrite(120, TimeUnit.SECONDS)
                .removalListener(listener)
                .build(loader);

しかし、テストするためにこのようなことをすると:

System.out.println(myCache.get("100"));
System.out.println(myCache.get("103"));
System.out.println(myCache.get("110"));
System.out.println(myCache).get("111"));
Thread.sleep(230000);
System.out.println(myCache.size());

まだゼロではなく2になっています。なんで ?120 秒以上経過した後、間違っていなければサイズがゼロになっているはずです。

MyCacheLoader

public class MyCacheLoader extends CacheLoader<String,String>     {
    @Override
    public String load(String key) throws Exception {
        return key;
    }
}

MyRemovalListener

public class MyRemovalListener implements RemovalListener<String,String> {

    Logger logger = LoggerFactory.getLogger(MyRemovalListener.class);
    @Override
    public void onRemoval(RemovalNotification<String, String> removalNotification) {
        logger.info("Message with message Id ("+
                removalNotification.getKey()+ ") is removed.");
        System.out.println("Message with message Id ("+
                removalNotification.getKey()+ ") is removed.");
    }
}
4

1 に答える 1

8

まず、Guava の Cache API を初めて使用する場合、またはMap<K, V>インターフェイスを実装しているかのように扱っている場合は、 CachesExplained · google/guava Wikiを読むことをお勧めします。「ACacheは に似てConcurrentMapいますが、まったく同じではありません。」

たとえば、「このキャッシュ内のエントリのおおよそCache.size()の数を返す」(強調を追加) は、「このマップ内のキーと値のマッピングの数を返す」とは異なります。Map.size()

そのため、正確な数のエントリがCache.size()返されることは期待できませんが、おおよその数が返されます。私は確かに主張しますが、一般的には主張しません。Cache.size()Map.size()

第二に、「で構築されたキャッシュは、クリーンアップを実行CacheBuilder、値を「自動的に」、または値の有効期限が切れた直後に、またはそのようなもので削除します。代わりに、書き込み操作中、または書き込みが失敗した場合は時折の読み取り操作中に、少量のメンテナンスを実行します。レア" (いつクリーンアップが行われるのか? · CachesExplained · google/guava Wiki ).

次の例を検討してください。

LoadingCache<String, String> myCache = CacheBuilder.newBuilder()
        .concurrencyLevel(10)
        .weakKeys()
        .maximumSize(2)
        .expireAfterWrite(120, TimeUnit.MILLISECONDS)
        .removalListener(notification ->
                System.out.println(notification.getKey() + " removed"))
        .build(new CacheLoader<String, String>() {
            @Override
            public String load(String key) throws Exception {
                System.out.println("loading " + key);
                return UUID.randomUUID().toString();
            }
        });
myCache.get("100");
myCache.get("103");
myCache.get("110");
myCache.get("111");
Thread.sleep(230);
System.out.println(myCache.size());
myCache.get("111");
System.out.println(myCache.size());

出力:

loading 100
loading 103
loading 110
100 removed
loading 111
103 removed
2
110 removed
111 removed
loading 111
1

ご覧のとおり、ここでの削除は、アイテムがキャッシュから読み取られるまで発生しません。

詳細とより詳細な例については、 How does timed cache expiry work?の私の回答を参照してください。

于 2016-09-08T13:35:44.447 に答える