这就是我要解决的问题--我有一个对象,它有两个整型字段,我想要缓存它
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返回两个不同的对象(例如,如果对象在调用期间位于磁盘上,并且被序列化了两次,每次调用一次)。
发布于 2010-11-19 00:34:19
你完全有可能得到列表的两个不同的实例(或者任何可序列化的)!试试这个:
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)缓存(从Ehcache2.1开始)。
另一种解决方案是只有一个可以修改列表的线程。如果你有多个线程可以修改它,并且你没有在缓存上使用锁,那么你就可以得到你所描述的不确定的结果!
发布于 2010-11-10 06:34:54
我有一种不同的方法,我刚刚在一篇关于地理范围搜索的文章中读到了。
在缓存中放入两个键值对:一个只有x作为键,另一个x和y都有键。在缓存中查找时,首先查找x-and-y键。如果它在那里,你就找到了一个完美的匹配。如果不存在,则查找x键,并可能找到具有不同y值的匹配项。
发布于 2010-11-16 07:55:30
我会创建一个方法来获取对象的值。使用信号量限制对该方法的访问(或使用synchronized)。
在您的方法中,测试X-only匹配,如果返回多个结果,则文本为XY匹配。
一旦对象位于缓存之外,对该对象的任何修改也将修改缓存中的对象(因为它们指向相同的实例)。
如果您想要格外小心,可以使用同步方法来获取/设置MyObject中的成员变量,并包含一个作为MyObject实例的锁。
public void setX( int x ) {
synchronized( this ) {
this.x = x;
}
}https://stackoverflow.com/questions/4139084
复制相似问题