Guava CacheBuilder Cache RemovalListener onRemoval每次都会被调用,但条目被删除

Kir*_*ran 5 java guava

如果没有写入密钥,我已经创建了一个基于Guava CacheBuilder的缓存,有效期为5秒.已向其添加了removeListener,用于打印要删除的键/值对.我观察到的是,只有第一次调用侦听器的onRemoval方法.第二次删除条目时不会调用它.(实际删除发生.只是removeListener的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);

  }

}
Run Code Online (Sandbox Code Playgroud)

输出如下:

Initial Insert: {MyKey=FirstValue}
After 4 seconds: {MyKey=FirstValue}
removal: MyKey/FirstValue
After 1 more second: {MyKey=SecondValue}
After 4 more seconds: {}
Run Code Online (Sandbox Code Playgroud)

Fra*_*eau 8

删除实际上并不是直接发生的:Guava没有自己的清理线程来删除过期的条目.删除通常发生在高速缓存的同一段中写入时,或者在经过一定时间后读取时(为了分摊删除成本).但是,虽然该条目仍然存在,但它被视为已过期,这就是为什么它不打印.

引用CacheBuilder的javadoc:

如果请求expireAfterWrite或expireAfterAccess,则可以在每次高速缓存修改,偶尔的高速缓存访​​问或对Cache.cleanUp()的调用时逐出条目.过期的条目可以在Cache.size()中计算,但对于读取或写入操作永远不可见.