如何获得 TrieMap.getOrElseUpdate 的真正原子更新

How to get truly atomic update for TrieMap.getOrElseUpdate

据我了解,TrieMap.getOrElseUpdate 仍然不是真正的原子,并且 this 仅修复 returned 结果(在此之前它可能 return 不同调用者的不同实例修复),因此更新程序函数仍可能被调用多次,如文档(2.11.7)所述:

Note: This method will invoke op at most once. However, op may be invoked without the result being added to the map if a concurrent process is also trying to add a value corresponding to the same key k.

*我已经手动检查了 2.11.7,仍然 "at least once"

如何保证一次性调用(如果我对工厂使用TrieMap)?

我认为这个解决方案应该可以满足我的要求:

trait LazyComp { val get: Int }

val map = new TrieMap[String, LazyComp]()

val count = new AtomicInteger() //just for test, you don't need it

def getSingleton(key: String) = {
  val v = new LazyComp {
    lazy val get = {
      //compute something
      count.incrementAndGet() //just for test, you don't need it
    }
  }
  map.putIfAbsent(key, v).getOrElse(v).get
}

我相信,lazy val其实里面用的是synchronized。而且 get 里面的代码应该是

不过,性能可能会在未来得到改善:SIP-20

测试:

scala> (0 to 10000000).par.map(_ => getSingleton("zzz")).last
res8: Int = 1

P.S。 Java 在 ConcurrentHashMap 上有 computeIfAbscent 方法,我也可以使用它。