【发布时间】:2015-11-24 18:23:48
【问题描述】:
我有一个高吞吐量低延迟应用程序(3000 请求/秒,每个请求 100 毫秒),我们大量使用 Java 8 ConcurrentHashMap 来执行查找。通常这些地图由一个后台线程更新,多个线程从这些地图中读取。
我看到了性能瓶颈,在分析时我发现 ConcurrentHashMap.get 是热点并且占用了大部分时间。
在另一种情况下,我看到 ConcurrentHashMap.computeIfAbsent 是热点,尽管映射函数的延迟非常小,并且配置文件显示 computeIfAbsent 花费 90% 的时间执行自身,并且执行映射的时间非常少 -功能。
我的问题是有什么办法可以提高性能?我有大约 80 个线程同时从 CHM 读取数据。
【问题讨论】:
-
@AmmSokun
computeIfAbsent在读取和潜在计算值之前悲观地锁定。在 32+ 核心机器上,在竞争下似乎确实更快,但在其他方面,乐观读取要快得多。当读取成功的可能性很高时尤其如此,例如在缓存中。当它确实翻转时,差异就不那么明显了,因此预筛选是一个净收益。 -
在 jdk 8 中,该参数只是尺寸提示,不再使用了
-
其实问题是"3000 Request/Sec"。每个请求执行多少个 CHM 方法调用?由于每个请求花费 100 毫秒,因此 CHM 调用应该是其中的一小部分,或者每个请求必须超过 1 个。换句话说,这个问题提供了非常模糊的数据,你甚至没有包括你的分析器输出。
-
@AmmSokun 变量
f表示找到的else块,桶链使用synchronized (f)。 Doug Lea recommends 为小于 32 路机器的预筛选优化,但必须展望未来,该优化时间太短而无法采用。 -
另一段有趣的代码
chm.put(key, System.currentTimeMillis(),这是在每个请求的平均大小为 100 的循环中完成的,我认为chm.get(key).setTime(System.currentTimeMillis())会更好。伙计们怎么说?
标签: performance java-8 concurrenthashmap