繁体   English   中英

HashMap vs ConcurrentHashMap vs LoadingCache(番石榴)

[英]HashMap vs ConcurrentHashMap vs LoadingCache(Guava)

要在 spring 引导应用程序中本地缓存一些数据,哪种技术在读/写操作方面会更好? HashMap vs ConcurrentHashMap vs LoadingCache(Guava library) 我分别尝试了写和读操作,HashMap最快,LoadingCache最慢,那我们为什么要使用LoadingCache呢?

编辑:应用程序是多线程的。 缓存的最大大小、到期时间等功能可能会受到影响。 此外,主要动机是提高读取速度。

如果您的应用程序是多线程的并且缓存由线程共享,那么HashMap不是一个选项。 它不是线程安全的,如果你用锁等保护它,锁定很容易成为并发瓶颈。

如果你的应用程序需要缓存是 LRU 或者有一些其他的“智能”策略来决定驱逐什么,那么ConcurrentHashMap并没有提供一个很好的方法来做到这一点。 如果您希望您的缓存对 memory 压力敏感(例如使用弱引用键),那么ConcurrentHashMap也不会这样做。

这就是 Guava Cache类的用武之地。阅读本文以了解它们提供的功能。


底线是,虽然HashMap在单线程基准测试中性能最高,但它可能无法提供您需要的所有功能。 性能不是一切。

我的建议是先让代码正常工作……然后再考虑优化它的方法。 偶尔中断或填满 memory 的超快速缓存实现不是一个好主意。 而且很有可能缓存读/写性能无论如何都不重要。

关于性能,它取决于数据的大小和读取之间的修改比率。 这是一个建议:

Static 数据:如果您的数据是 static,请在构造函数中初始化只读 map,如下所示:

final Map map;
MyClass(Map inputMap) {
  map = Map.copyOf(inputMap);
}
Object get(Object key) {
  return map.get(key);
}

罕见的修改:如果你有很少的修改并且数据不是太大:

volatile Map map = Map.of();
Object synchronized put(Object key, Object value) {
  Map mutable = new HashMap(map);
  mutable.put(key, value);
  map = Map.copyOf(mutable);
}
Object get(Object key) {
  return map.get(key);
}

The Map.copyOf is available since Java 9. It creates an immutable hash table, that is using an open addressing scheme, unlike HashMap . 这将比HashMap更快。 您还可以在多线程环境中将HashMap与上述方案一起使用,因为它一旦创建就不会被修改。

需要synchronized ,以确保在多个线程同时使用put时不使用更新。 需要volatile以确保更新在其他线程中可见。

主要动机是提高读取速度。

因此,上述解决方案将提供最佳读取速度,但会影响更新速度。

大量数据和/或大量修改:使用ConcurrentHashMap

即使有轻微的性能优势,我还是建议使用ConcurrentHashMap ,因为:

  • 它不太容易出错,并且ConcurrentHashMap被证明可以工作。 你会用多线程编写单元测试来证明你的代码可以正常工作吗?
  • 更少的代码。 更少的错误
  • 更少的代码。 减少您的开发人员的困惑
  • 使用模式可能会随着时间的推移而改变,而您自己培养的“性能改进”将变成“性能问题”。

脚注:

缓存的使用

Cache 和LoadingCache : Guava LoadingCache旨在与CacheLoader一起使用。 缓存加载器可用于使缓存自动填充缓存和/或进行刷新。 与此同时,Guava 缓存已经过时,我建议在寻找在 Java 堆中工作的缓存解决方案时查看 Caffin 或cache2k

缓存在读取路径中总是有额外的开销,因为它需要做一些簿记才能知道当前访问了哪些条目。 至少根据我的(免责声明...)基准测试,cache2k 的开销是最小的。

Spring 开机

当与 Spring 缓存抽象一起使用时,例如使用@Cacheable ,在实现中不会有很大的性能差异,因为缓存抽象也有非常相关的开销。

Spring 中基于ConcurrentHashMap的简单cache实现仅用于测试和原型设计。 我建议始终尽快使用真正的缓存实现并设置合理的资源限制。

分析和优化整个应用程序

您所做的每项优化都有权衡,因此您应该始终查看整个应用程序并将“优化”与可能的最简单或最常见的解决方案进行比较。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM