使用java ConcurrentHashMap实现缓存

我想在Web java应用程序中实现对重量级对象的简单缓存。 但我无法弄清楚如何正确地做到这一点。

我错过了什么或ConcurrentHashMap方法(putIfAbsent,…)是不够的,需要额外的同步?

是否有更好的简单API(在内存中,没有外部配置)来做到这一点?

P.

如果临时为您尝试缓存的事物安装多个实例是安全的,那么您可以像这样执行“无锁”缓存:

public Heavy instance(Object key) { Heavy info = infoMap.get(key); if ( info == null ) { // It's OK to construct a Heavy that ends up not being used info = new Heavy(key); Heavy putByOtherThreadJustNow = infoMap.putIfAbsent(key, info); if ( putByOtherThreadJustNow != null ) { // Some other thread "won" info = putByOtherThreadJustNow; } else { // This thread was the winner } } return info; } 

多个线程可以“竞争”以创建和添加密钥项,但只有一个应该“赢”。

除了Ken的答案之外,如果创建一个后来被扔掉的重量级对象是不可接受的(你想保证每个键只创建一个对象,出于某种原因),那么你可以通过….实际上,别。 不要自己动手。 使用google-collections (现为番石榴 ) MapMaker类 :

 Map cache = new MapMaker() .makeComputingMap(new Function() { public HeavyData apply(KeyType key) { return new HeavyData(key); // Guaranteed to be called ONCE for each key } }); 

然后一个简单的cache.get(key)可以工作了 ,完全免除了你不必担心并发和同步化的棘手问题。

请注意,如果您想添加一些更高级的function,例如到期,那就是

 Map<....> cache = new MapMaker<....>() .expiration(30, TimeUnit.MINUTES) .makeComputingMap(.....) 

如果需要,您还可以轻松地为键或数据使用软值或弱值(有关详细信息,请参阅Javadoc)

您可以使用轻工厂对象来创建活动缓存,而不是将“重物”放入缓存中。

 public abstract class LazyFactory implements Serializable { private Object _heavyObject; public getObject() { if (_heavyObject != null) return _heavyObject; synchronized { if (_heavyObject == null) _heavyObject = create(); } return _heavyObject; } protected synchronized abstract Object create(); } // here's some sample code // create the factory, ignore negligible overhead for object creation LazyFactory factory = new LazyFactory() { protected Object create() { // do heavy init here return new DbConnection(); }; }; LazyFactory prev = map.pufIfAbsent("db", factory); // use previous factory if available return prev != null ? prev.getObject() : factory.getObject; 

ConcurrentHashMap应该足以满足您的需求putIfAbsent是线程安全的。

不知道你能得到多少简单

 ConcurrentMap myCache = new ConcurrentHashMap(); 

保罗

我意识到这是一个旧post,但在java 8中,这可以在不使用ConcurrentHashMap创建可能未使用的重型对象的情况下完成。

 public class ConcurrentCache4 { public static class HeavyObject { } private ConcurrentHashMap cache = new ConcurrentHashMap<>(); public HeavyObject get(String key) { HeavyObject heavyObject = cache.get(key); if (heavyObject != null) { return heavyObject; } return cache.computeIfAbsent(key, k -> new HeavyObject()); } }