使用 Java ConcurrentHashMap 实现缓存
2022-09-02 23:34:35
我想在Web Java应用程序中实现重量级对象的简单缓存。但是我不知道如何正确地做到这一点。
我是否遗漏了什么或 ConcurrentHashMap 方法(putIfAbsent,...)还不够,需要额外的同步?
有没有更好的简单API(在内存存储中,没有外部配置)来做到这一点?
P.
我想在Web Java应用程序中实现重量级对象的简单缓存。但是我不知道如何正确地做到这一点。
我是否遗漏了什么或 ConcurrentHashMap 方法(putIfAbsent,...)还不够,需要额外的同步?
有没有更好的简单API(在内存存储中,没有外部配置)来做到这一点?
P.
进一步 Ken 的答案,如果创建一个后来被丢弃的重量级对象是不可接受的(出于某种原因,您希望保证每个键只创建一个对象),那么您可以通过....实际上,不要。不要自己动手。使用谷歌收藏(现在的番石榴)MapMaker类:
Map<KeyType, HeavyData> cache = new MapMaker<KeyType, HeavyData>()
.makeComputingMap(new Function<KeyType, HeavyData>() {
public HeavyData apply(KeyType key) {
return new HeavyData(key); // Guaranteed to be called ONCE for each key
}
});
然后,一个简单的方法就可以工作,完全消除您不必担心并发和同步的棘手方面。cache.get(key)
请注意,如果您想添加一些更高档的功能,例如过期,则只需
Map<....> cache = new MapMaker<....>()
.expiration(30, TimeUnit.MINUTES)
.makeComputingMap(.....)
如果需要,您还可以轻松地对键或数据使用软值或弱值(有关详细信息,请参阅 Javadoc)
如果暂时为您尝试缓存的内容设置多个实例是安全的,则可以执行“无锁”缓存,如下所示:
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;
}
多个线程可以“争用”为密钥创建和添加项目,但只有一个线程应该“获胜”。