java Ehcache - 使用 List<Integer> 作为缓存值
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/4139084/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Ehcache - using a List<Integer> as the cache value
提问by Gandalf
So here is the problem I am trying to solve - I have an Object with two integer fields that I want to cache
所以这是我要解决的问题 - 我有一个对象,其中包含两个我想要缓存的整数字段
public class MyObject {
int x;
int y;
....
}
Now the field x
is what I mainly match on - but there can be duplicates in which case I want to fall back on the second field (so that this.x=that.x and this.y=that.y). y can only be 25 distinct values. Now I know I could just combine the two as a String and use that as the cache key, but then I would have to try x+[25 possible values]
to actually determine if it was not in the cache - making cache misses very expensive. I was thinking of trying to store a List<Integer>
as the cache value for the field x
and then if their was more then one, iterate down the list and look for a match on y
.
现在该字段x
是我主要匹配的字段- 但可能存在重复项,在这种情况下我想退回到第二个字段(因此 this.x=that.x 和 this.y=that.y)。y 只能是 25 个不同的值。现在我知道我可以将两者组合为一个字符串并将其用作缓存键,但是我必须尝试x+[25 possible values]
实际确定它是否不在缓存中 - 使缓存未命中非常昂贵。我正在考虑尝试将 a 存储List<Integer>
为该字段的缓存值x
,然后如果它们超过一个,则向下迭代列表并查找y
.
Now if I use a ConcurrentList
(or a Set if I care about duplicates - lets ignore that for now) will multiple threads be able to add to it and then put it back into the cache without race conditions? Is it possible that Ehcache might return two different List Objects to two threads and then when they add their new value to the list and attempt to put it back to the cache I could get undeterministic results? Do you see a better way of constructing this cache?
现在,如果我使用 a ConcurrentList
(或 Set 如果我关心重复项 - 现在让我们忽略它)是否可以将多个线程添加到它然后将它放回缓存中而没有竞争条件?Ehcache 是否有可能将两个不同的列表对象返回给两个线程,然后当他们将新值添加到列表中并尝试将其放回缓存时,我可能会得到不确定的结果?您是否看到构建此缓存的更好方法?
EDIT : I appreciate the answers below, but everyone seems to be missing the main point. Will this work? Could Ehcache actually return two different objects for the same cacheKey (say if the object was on disk during the call and it's serialized it twice, once for each call).
编辑:我很欣赏下面的答案,但每个人似乎都没有抓住要点。这会奏效吗?Ehcache 实际上是否可以为同一个 cacheKey 返回两个不同的对象(假设对象在调用期间是否在磁盘上并且它被序列化了两次,每次调用一次)。
采纳答案by Chris Lercher
It's absolutely possible that you get two different instances of your List (or of any Serializable)! Try this:
您绝对有可能获得 List(或任何 Serializable)的两个不同实例!试试这个:
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();
}
I used the following in ehcache.xml:
我在 ehcache.xml 中使用了以下内容:
<cache name="smallCache"
maxElementsInMemory="1"
eternal="true"
overflowToDisk="true"
diskPersistent="true"
maxElementsOnDisk="200"
memoryStoreEvictionPolicy="LRU"
transactionalMode="off"
>
</cache>
One solution may be to use Explicit Locking, which seems to be available for standalone (non-Terracotta) caches, too (since ehcache 2.1).
一种解决方案可能是使用Explicit Locking,它似乎也可用于独立(非 Terracotta)缓存(自 ehcache 2.1 起)。
Another solution would be to only have one thread which can modify the List. If you have multiple threads which can modify it, and you don't use locking on the cache, then you can get exactly the undeterministic results you described!
另一种解决方案是只有一个线程可以修改列表。如果您有多个可以修改它的线程,并且您不在缓存上使用锁定,那么您可以获得您描述的完全不确定的结果!
回答by Christian Semrau
I have a different approach for you, which I just read in an article about geographic range searches.
我有一个不同的方法,我刚刚在一篇关于地理范围搜索的文章中读到。
Put two key-value pairs in the cache: One with only x as the key, and one with both x and y as the key. When you look in the cache, look for the x-and-y key first. If it's there, you found a perfect match. If it's not there, look for the x key and possibly find a match with different y value.
将两个键值对放入缓存中:一个只有 x 作为键,另一个同时有 x 和 y 作为键。当您查看缓存时,首先查找 x-and-y 键。如果它在那里,你就找到了一个完美的匹配。如果不存在,请查找 x 键并可能找到具有不同 y 值的匹配项。
回答by austin.jones
I would create a method to get the value for your object. Use a semaphore to restrict access to the method (or use synchronized).
我会创建一个方法来获取您的对象的值。使用信号量来限制对方法的访问(或使用同步)。
In your method, test for X-only matches, and if that returns multiple results, text for XY matches.
在您的方法中,测试仅 X 匹配,如果返回多个结果,则 XY 匹配的文本。
Once the object is outside of the cache, any modifications to the object will modify the object within the cache as well (since they are pointing to the same instance).
一旦对象在缓存之外,对对象的任何修改也将修改缓存内的对象(因为它们指向同一个实例)。
If you want to be super careful, use synchronized methods to get/set the member variables within the MyObject, and include a lock which is the MyObject instance.
如果您想非常小心,请使用同步方法来获取/设置 MyObject 中的成员变量,并包含一个锁,即 MyObject 实例。
public void setX( int x ) {
synchronized( this ) {
this.x = x;
}
}
回答by towi
- Make a Key class of
x
andy
, ie.class Key { int x,y }
- implement a separate comparison operation for you "lexical ordering" on
x
andy
, - put it into a
Map<Key,Value>
- 制作一个 Key 类
x
和y
,即。class Key { int x,y }
- 实现你“词汇顺序”在一个单独的比较操作
x
和y
, - 把它放进一个
Map<Key,Value>
回答by Knubo
You could use a Map containing a sorted set as the value. The first map could index on X and then you can pick the first element from the sorted set where the sort is based on Y.
您可以使用包含排序集的 Map 作为值。第一个映射可以在 X 上建立索引,然后您可以从排序基于 Y 的排序集中挑选第一个元素。
I guess the google collection api got lots of neat stuff that you could use, for instance the SortedSetMultimap:
我想 google collection api 有很多你可以使用的整洁的东西,例如 SortedSetMultimap: