Java – ehcache – uses list as the cache value
So this is the problem I'm trying to solve - I have an object with two integer fields, and I want to cache
public class MyObject { int x; int y; .... }
Now the field x is my primary match – but there may be duplication, in which case I want to go back to the second field (so this. X = that. X and this. Y = that. Y) Y can only be 25 different values Now I know I can combine the two into a string and use it as a cache key, but I have to try x [25 possible values] to actually determine if it's not in the cache - making cache misses very expensive I'm thinking about trying to store list < integer > as the cached value of field x, and then if they exceed 1, traverse the list down and find a match on y
Now, if I use concurrentlist (or if I care about duplicates, let's ignore it for a while), can I add multiple threads to it and put them back in the cache without race conditions? Is it possible that ehcache may return two different list objects to two threads, and then when they add a new value to the list and try to put it back into the cache, I may get uncertain results? Do you see a better way to build this cache?
Editor: I appreciate the answers below, but everyone seems to miss the point Will this work? Ehcache can actually return two different objects for the same cachekey (for example, whether the object is on disk during the call and it is serialized twice, one call at a time)
Solution
You can get two different instances of list (or any serializable)! Try this:
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'm in ehcache XML uses the following:
<cache name="smallCache" maxElementsInMemory="1" eternal="true" overflowToDisk="true" diskPersistent="true" maxElementsOnDisk="200" memoryStoreEvictionPolicy="LRU" transactionalMode="off" > </cache>
One solution might be to use explicit locking, which also seems to be available for stand-alone (non terracotta) caching (since ehcache 2.1)
Another solution is that there is only one thread that can modify the list If you have multiple threads that can modify it and you don't use locking on the cache, you can get the completely uncertain results you describe!