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

时间:2016-02-18 14:59:22

标签: scala concurrency compare-and-swap

据我了解,TrieMap.getOrElseUpdate仍然不是真正的原子,this只修复了返回的结果(它可能会在此修复之前为不同的调用者返回不同的实例),因此仍可能调用updater函数有几次,正如文件(2.11.7)所说:

  

注意:此方法最多只调用一次操作。但是,如果并发进程也尝试添加对应于相同键k的值,则可以调用op而不将结果添加到映射中。

*我已经手动检查了2.11.7,仍然"至少一次"

如何保证一次性通话(如果我为工厂使用TrieMap)?

1 个答案:

答案 0 :(得分:2)

我认为这个解决方案应该符合我的要求:

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实际上使用了内部同步。而且get里面的代码也应该是safe from exceptions

但是,将来可以提高绩效:SIP-20

测试:

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

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