Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/328.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java Guava CacheBuilder Cache RemovalListener OnRemoving不';虽然条目被删除,但不会每次都被调用_Java_Guava - Fatal编程技术网

Java Guava CacheBuilder Cache RemovalListener OnRemoving不';虽然条目被删除,但不会每次都被调用

Java Guava CacheBuilder Cache RemovalListener OnRemoving不';虽然条目被删除,但不会每次都被调用,java,guava,Java,Guava,我已经创建了一个基于Guava CacheBuilder的缓存,如果未写入密钥,则该缓存的过期时间为5秒。已向其添加了一个removalListener,用于打印要删除的键/值对。 我所观察到的是,侦听器的onremove方法仅在第一次被调用。它不会在第二次删除条目时被调用。(实际的删除发生了。只有removalListener的OnRemovement方法没有被调用) 我做错什么了吗?有人能帮忙吗?提前谢谢。 这是我的密码: import java.util.Map; import java.

我已经创建了一个基于Guava CacheBuilder的缓存,如果未写入密钥,则该缓存的过期时间为5秒。已向其添加了一个removalListener,用于打印要删除的键/值对。 我所观察到的是,侦听器的onremove方法仅在第一次被调用。它不会在第二次删除条目时被调用。(实际的删除发生了。只有removalListener的OnRemovement方法没有被调用)

我做错什么了吗?有人能帮忙吗?提前谢谢。 这是我的密码:

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);

  }

}

删除实际上并不是直接发生的:Guava没有自己的清理线程来删除过期的条目。删除通常发生在缓存的同一段中发生写操作时,或者在经过一定时间(以分摊删除成本)的读取过程中。然而,当条目仍然存在时,它被视为过期,这就是为什么它没有被打印出来

引述:

如果请求expireAfterWrite或expireAfterAccess,则在每次修改缓存、偶尔访问缓存或调用cache.cleanUp()时,都可能逐出条目。过期的条目可以在Cache.size()中计数,但对读或写操作来说永远不可见

如果请求
expireAfterWrite
expireAfterAccess
,则每次修改缓存、偶尔访问缓存或调用
cache.cleanUp()
时,都可能会逐出条目。过期的条目可以在
Cache.size()
中计数,但在读写操作中永远不可见


从长远来看,这将消耗所有堆内存,或导致不使用任何缓存的其他模块内存不足。

作为Guava
缓存的替代方案,您可以使用“基于Java 8的高性能、接近最佳缓存库”

它有“Google Guava-inspired API”,并定期执行逐出,因此它可能更适合您的用例(如果您担心内存不能半自动释放)。见:

在写入期间定期维护,偶尔在读取期间执行过期。到期事件的调度和触发在摊销O(1)时间内执行


除了实际问题之外,还可以看到:您可以通过使用来模拟可以随意操纵的时钟()来增强测试。这将加快你的测试速度,使他们能够适应微妙的时间问题。谢谢皮兰贾。我一定会看看的!谢谢你,弗兰克。Cache.cleanUp()似乎可以做到这一点。只是想知道如果经常使用它会对性能产生什么影响。我面临的问题是,当缓存项被删除时,我需要该消息,因为系统需要根据删除情况执行其他操作。@Kiran这取决于缓存的访问模式。如果调用过多,则在运行
Cache.cleanUp()
@Kiran时会添加一些争用:缓存越忙,自动进行的清理就越多,因此在高峰时间,您可能会关闭手动
清理
。OTOH,我相信我已经看到了对
cleanUp
的单个调用并没有删除所有垃圾。如果这是真的,也许你应该咨询Guava的伙计们。逻辑是在偶尔的缓存读取、每次缓存写入或调用
cache.cleanup()
时自动进行清理。在您的测试中,我会继续调用
cleanUp()
,但这在生产中应该不是必需的;但是避免在生产环境中调用
Cache.cleanUp()
。我所知道的唯一例外是具有非常大对象的极低吞吐量缓存。毕竟,如果你的缓存被实际使用,它将被足够快地清理干净。
Initial Insert: {MyKey=FirstValue}
After 4 seconds: {MyKey=FirstValue}
removal: MyKey/FirstValue
After 1 more second: {MyKey=SecondValue}
After 4 more seconds: {}