7

キーが書き込まれていない場合、5秒の有効期限でGuavaCacheBuilderベースのキャッシュを作成しました。削除されるキーと値のペアを出力するremovalListenerを追加しました。私が観察したのは、リスナーのonRemovalメソッドが最初に呼び出されるだけであるということです。エントリが2回削除されたときに呼び出されることはありません。(実際の削除が行われます。removalListenerのonRemovalメソッドだけは呼び出されません)。

私は何か間違ったことをしていますか?誰かが助けることができますか?前もって感謝します。これが私のコードです:

import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.TimeUnit;

import com.google.common.cache.Cache;
import com.google.common.cache.CacheBuilder;
import com.google.common.cache.RemovalListener;
import com.google.common.cache.RemovalNotification;


public class TestCacheBuilder {

  public static void main(String[] args) {
    try {
      new TestCacheBuilder();
    }catch (Exception e){      
     e.printStackTrace(); 
    }
  }

  public TestCacheBuilder() {

    Cache<String, String> myCache = CacheBuilder.newBuilder()
        .expireAfterWrite(5, TimeUnit.SECONDS)
        .removalListener(new RemovalListener<String, String>() {
          public void onRemoval(RemovalNotification<String, String> removal) {
            System.out.println("removal: "+removal.getKey()+"/"+removal.getValue());
          }          
        })
        .build();


    Map<String, String> inMap = myCache.asMap();

    inMap.put("MyKey", "FirstValue");

    System.out.println("Initial Insert: "+inMap);

    //Wait 16 seconds

    try {
      Thread.sleep(4000);
    } catch(InterruptedException ex) {
        Thread.currentThread().interrupt();
    }

    System.out.println("After 4 seconds: " + inMap);

    inMap.put("MyKey", "SecondValue");

    try {
      Thread.sleep(1000);
    } catch(InterruptedException ex) {
        Thread.currentThread().interrupt();
    }

    System.out.println("After 1 more second: " + inMap);

    try {
      Thread.sleep(4000);
    } catch(InterruptedException ex) {
        Thread.currentThread().interrupt();
    }


    System.out.println("After 4 more seconds: " + inMap);

  }

}

出力は次のとおりです。

Initial Insert: {MyKey=FirstValue}
After 4 seconds: {MyKey=FirstValue}
removal: MyKey/FirstValue
After 1 more second: {MyKey=SecondValue}
After 4 more seconds: {}
4

3 に答える 3

12

削除は実際には直接行われません。Guavaには、期限切れのエントリを削除するための独自のクリーニングスレッドがありません。削除は通常、キャッシュの同じセグメントに書き込みがある場合、または読み取り中に一定の時間が経過した場合に発生します(削除のコストを償却するため)。ただし、エントリがまだ存在している間は、有効期限が切れていると見なされるため、印刷されません。

CacheBuilderのjavadocを引用する:

ExpiredAfterWriteまたはexpireAfterAccessが要求された場合、各キャッシュの変更、不定期のキャッシュアクセス、またはCache.cleanUp()の呼び出しでエントリが削除される場合があります。期限切れのエントリはCache.size()でカウントされる場合がありますが、読み取りまたは書き込み操作で表示されることはありません。

于 2012-08-28T10:48:07.213 に答える