Groovy 抽象 ConcurrentMap 中的错误?

Bug in Groovy AbstractConcurrentMap?

AbstractConcurrentMap是Groovy中的核心class,用于存储运行时添加到Groovyclasses中的动态属性。我将 Grails 2.1.2 与 Groovy 1.8.8 一起使用,但我认为该问题存在于所有 Groovy 版本中(链接的源代码适用于 Groovy 版本 2.4.3) .

问题发生在内部 class 段的 put() 方法(第 105 行):

因此发生了以下步骤:

  1. 地图状态:threshold = 786432; count=786432
  2. 新元素已插入地图:count = 786433; threshold = 786432
  3. 因为新计数会大于阈值 rehash() 发生了
  4. rehash() 发现,大多数对象都被垃圾收集了,因此它不会增加段的大小,但是无论如何它将所有对象从一个 table 复制到另一个(System.arrayCopy()).
  5. rehash() 将内部计数设置为新值,该值更小,因为许多对象被垃圾回收(软引用),比方说:count = 486 000
  6. put() 继续,忽略 count = 486 000 并将计数设置为 count = 786433
  7. 插入了另一个元素,但在此状态下,计数仍然大于阈值,因此重新哈希再次发生
  8. 从现在开始,添加到地图的每个元素都会触发 rehash(),这会对性能产生巨大影响。

在多线程环境中发生这种情况时,所有其他线程都在等待(停放)lock(),直到 rehash() 和 put() 完成(然后下一个线程再次执行 rehash()) .你可以想象这是什么性能影响...

我不明白尽管 class 被广泛使用,但这个错误如何能够在这么多版本中幸存下来而没有人注意到。也许我遗漏了什么?

建议解决方案:

重新哈希完成后更新 c 变量。 在第 105 行和第 106 行之间添加:

c = count + 1

此错误已在 Groovy JIRA https://issues.apache.org/jira/browse/GROOVY-7448 上报告,现已修复。

Fix Version/s:
2.4.4, 2.5.0-beta-1