代码之家  ›  专栏  ›  技术社区  ›  Gandalf

Ehcache-使用List<Integer>作为缓存值

  •  6
  • Gandalf  · 技术社区  · 14 年前

    public class MyObject {
       int x;
       int y;
       ....
    }
    

    现在的领域 x 是我主要匹配的——但是也可能有重复的,在这种情况下,我想回到第二个字段(所以this.x=that.x and this.y=that.y)。y只能是25个不同的值。现在我知道我可以将两者组合成一个字符串并将其用作缓存键,但是之后我必须尝试 x+[25 possible values] 要真正确定它是否不在缓存中-使缓存未命中非常昂贵。我在考虑储存一个 List<Integer> y .

    如果我用 ConcurrentList

    编辑:我很欣赏下面的答案,但每个人似乎都忽略了要点。这行吗?Ehcache是否真的为同一个cacheKey返回两个不同的对象(比如,如果对象在调用期间在磁盘上,并且它被序列化了两次,每次调用一次)。

    5 回复  |  直到 14 年前
        1
  •  5
  •   Chris Lercher    14 年前

    你的列表(或任何可序列化的)绝对有可能有两个不同的实例!试试这个:

    public static void main(final String[] args) throws Exception {
        final Cache cache = CacheManager.getInstance().getCache("smallCache");
    
        final List<String> list = new ArrayList<String>();
        cache.put(new Element("A", list));
    
        /* We put in a second element. Since maxElementsInMemory="1", this means
         * that "A" will be evicted from memory and written to disk. */
        cache.put(new Element("B", new ArrayList<String>())); 
        Thread.sleep(2000); // We need to wait a bit, until "A" is evicted.
    
        /* Imagine, the following happens in Thread 1: */
            final List<String> retrievedList1 =
                       (List<String>) cache.get("A").getValue();
            retrievedList1.add("From Thread 1");
    
        /* Meanwhile, someone puts something in the cache: */
            cache.put(new Element("C", new ArrayList<String>())); 
    
        Thread.sleep(2000); // Once again, we wait a bit, until "A" is evicted.
    
        /* Now the following happens in Thread 2: */
            final List<String> retrievedList2 =
                       (List<String>) cache.get("A").getValue();
            retrievedList2.add("From Thread 2");
            cache.put(new Element("A", retrievedList2));
    
        /* Meanwhile in Thread 1: */    
            cache.put(new Element("A", retrievedList1));
    
        /* Now let's see the result: */
        final List<String> resultingList =
                            (List<String>) cache.get("A").getValue();
        for (final String string : resultingList) {
            System.out.println(string);
        } /* Prints only "From Thread 1". "From Thread 2" is lost.
                     But try it with maxElementsInMemory="3", too!! */
    
        CacheManager.getInstance().shutdown();
    }
    

    我在ehcache.xml中使用了以下内容:

    <cache name="smallCache"
           maxElementsInMemory="1"
           eternal="true"
           overflowToDisk="true"
           diskPersistent="true"
           maxElementsOnDisk="200"
           memoryStoreEvictionPolicy="LRU"
           transactionalMode="off"
           >
    </cache>
    

    Explicit Locking ,它似乎也可用于独立(非Terracotta)缓存(自ehcache 2.1以来)。

    另一个解决方案是只有一个线程可以修改列表。如果您有多个可以修改它的线程,并且没有对缓存使用锁定,那么您可以得到您描述的不确定结果!

        2
  •  2
  •   Christian Semrau Louis Wasserman    14 年前

    我有一个不同的方法,我刚刚在一篇关于地理范围搜索的文章中读到。

    在缓存中查找时,请先查找x和y键。如果它在那里,你找到了一个完美的匹配。如果不存在,则查找x键并可能找到具有不同y值的匹配项。

        3
  •  1
  •   austin.jones    14 年前

    我将创建一个方法来获取对象的值。使用信号量限制对方法的访问(或使用synchronized)。

    在您的方法中,测试X-only匹配,如果返回多个结果,则测试XY匹配的文本。

    一旦对象位于缓存之外,对该对象的任何修改也将修改缓存内的对象(因为它们指向同一实例)。

    public void setX( int x ) {
         synchronized( this ) {
             this.x = x;
         }
    }
    
        4
  •  0
  •   Knubo    14 年前

    可以使用包含排序集的映射作为值。第一个映射可以在X上建立索引,然后可以从排序基于Y的排序集中选择第一个元素。

    我想google collection api提供了很多有用的东西,比如SortedSetMultimap:

    http://google-collections.googlecode.com/svn/trunk/javadoc/com/google/common/collect/SortedSetMultimap.html

        5
  •  0
  •   towi    14 年前
    • x y ,即。 class Key { int x,y }
    • 为您实现“词汇排序”的单独比较操作 是的 ,
    • Map<Key,Value>