首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >Ehcache -使用List<Integer>作为缓存值

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

Stack Overflow用户
提问于 2010-11-10 05:56:47
回答 5查看 18.3K关注 0票数 7

这就是我要解决的问题--我有一个对象,它有两个整型字段,我想要缓存它

代码语言:javascript
复制
public class MyObject {
   int x;
   int y;
   ....
}

现在,我主要匹配的是字段x --但也可以有重复的字段,在这种情况下,我想退回到第二个字段(以便this.x=that.x和this.y=that.y)。Y只能是25个不同的值。现在我知道我可以将这两个字符串组合成一个字符串,并将其用作缓存键,但然后我必须尝试x+[25 possible values]来确定它是否不在缓存中-这使得缓存未命中的代价非常高。我正在考虑尝试将List<Integer>存储为字段x的缓存值,然后如果它们的值大于1,则向下迭代列表并在y上查找匹配项。

现在,如果我使用一个ConcurrentList (或者一个Set,如果我关心重复的话-让我们暂时忽略它),多线程是否能够添加到它,然后将它放回缓存中,而不会出现争用条件?Ehcache有没有可能将两个不同的列表对象返回给两个线程,然后当它们将它们的新值添加到列表中并尝试将其放回缓存时,我可能会得到不确定的结果?您是否看到了构建此缓存的更好方法?

编辑:我很欣赏下面的答案,但似乎每个人都没有抓住要点。这样行得通吗?Ehcache是否真的可以为同一个cacheKey返回两个不同的对象(例如,如果对象在调用期间位于磁盘上,并且被序列化了两次,每次调用一次)。

EN

回答 5

Stack Overflow用户

回答已采纳

发布于 2010-11-19 00:34:19

你完全有可能得到列表的两个不同的实例(或者任何可序列化的)!试试这个:

代码语言:javascript
复制
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中使用了以下代码:

代码语言:javascript
复制
<cache name="smallCache"
       maxElementsInMemory="1"
       eternal="true"
       overflowToDisk="true"
       diskPersistent="true"
       maxElementsOnDisk="200"
       memoryStoreEvictionPolicy="LRU"
       transactionalMode="off"
       >
</cache>

一种解决方案可能是使用Explicit Locking,它似乎也可用于独立(非Terracotta)缓存(从Ehcache2.1开始)。

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

票数 5
EN

Stack Overflow用户

发布于 2010-11-10 06:34:54

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

在缓存中放入两个键值对:一个只有x作为键,另一个x和y都有键。在缓存中查找时,首先查找x-and-y键。如果它在那里,你就找到了一个完美的匹配。如果不存在,则查找x键,并可能找到具有不同y值的匹配项。

票数 2
EN

Stack Overflow用户

发布于 2010-11-16 07:55:30

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

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

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

如果您想要格外小心,可以使用同步方法来获取/设置MyObject中的成员变量,并包含一个作为MyObject实例的锁。

代码语言:javascript
复制
public void setX( int x ) {
     synchronized( this ) {
         this.x = x;
     }
}
票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/4139084

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档