Looking for simple Java in-memory cache
JavaCachingJava Problem Overview
I'm looking for a simple Java in-memory cache that has good concurrency (so LinkedHashMap isn't good enough), and which can be serialized to disk periodically.
One feature I need, but which has proved hard to find, is a way to "peek" at an object. By this I mean retrieve an object from the cache without causing the cache to hold on to the object any longer than it otherwise would have.
Update: An additional requirement I neglected to mention is that I need to be able to modify the cached objects (they contain float arrays) in-place.
Can anyone provide any recommendations?
Java Solutions
Solution 1 - Java
Since this question was originally asked, Google's Guava library now includes a powerful and flexible cache. I would recommend using this.
Solution 2 - Java
Ehcache is a pretty good solution for this and has a way to peek (getQuiet() is the method) such that it doesn't update the idle timestamp. Internally, Ehcache is implemented with a set of maps, kind of like ConcurrentHashMap, so it has similar kinds of concurrency benefits.
Solution 3 - Java
If you're needing something simple, would this fit the bill?
Map<K, V> myCache = Collections.synchronizedMap(new WeakHashMap<K, V>());
It wont save to disk, but you said you wanted simple...
Links:
(As Adam commented, synchronising a map has a performance hit. Not saying the idea doesn't have hairs on it, but would suffice as a quick and dirty solution.)
Solution 4 - Java
Another option for an in-memory java cache is cache2k. The in-memory performance is superior to EHCache and google guava, see the cache2k benchmarks page.
The usage pattern is similar to other caches. Here is an example:
Cache<String,String> cache = new Cache2kBuilder<String, String>() {}
.expireAfterWrite(5, TimeUnit.MINUTES) // expire/refresh after 5 minutes
.resilienceDuration(30, TimeUnit.SECONDS) // cope with at most 30 seconds
// outage before propagating
// exceptions
.refreshAhead(true) // keep fresh when expiring
.loader(new CacheLoader<String, String>() {
@Override
public String load(final String key) throws Exception {
return ....;
}
})
.build();
String val = cache.peek("something");
cache.put("something", "hello");
val = cache.get("something");
If you have google guava as dependency then trying out guava cache, may be a good alternative.
Solution 5 - Java
Try this:
import java.util.*;
public class SimpleCacheManager {
private static SimpleCacheManager instance;
private static Object monitor = new Object();
private Map<String, Object> cache = Collections.synchronizedMap(new HashMap<String, Object>());
private SimpleCacheManager() {
}
public void put(String cacheKey, Object value) {
cache.put(cacheKey, value);
}
public Object get(String cacheKey) {
return cache.get(cacheKey);
}
public void clear(String cacheKey) {
cache.put(cacheKey, null);
}
public void clear() {
cache.clear();
}
public static SimpleCacheManager getInstance() {
if (instance == null) {
synchronized (monitor) {
if (instance == null) {
instance = new SimpleCacheManager();
}
}
}
return instance;
}
}
Solution 6 - Java
You can easily use imcache. A sample code is below.
void example(){
Cache<Integer,Integer> cache = CacheBuilder.heapCache().
cacheLoader(new CacheLoader<Integer, Integer>() {
public Integer load(Integer key) {
return null;
}
}).capacity(10000).build();
}
Solution 7 - Java
Try @Cacheable
from jcabi-aspects. With a single annotation you make the entire method result cacheable in memory:
public class Resource {
@Cacheable(lifetime = 5, unit = TimeUnit.SECONDS)
public String load(URL url) {
return url.openConnection().getContent();
}
}
Also, read this article: http://www.yegor256.com/2014/08/03/cacheable-java-annotation.html
Solution 8 - Java
How about this: https://commons.apache.org/proper/commons-jcs/ (updated to new address, as JCS is now in Apache Commons)
Solution 9 - Java
Try Ehcache? It allows you to plug in your own caching expiry algorithms so you could control your peek functionality.
You can serialize to disk, database, across a cluster etc...