据我了解,TrieMap.getOrElseUpdate
仍然不是真正的原子,this只修复了返回的结果(它可能会在此修复之前为不同的调用者返回不同的实例),因此仍可能调用updater函数有几次,正如文件(2.11.7)所说:
注意:此方法最多只调用一次操作。但是,如果并发进程也尝试添加对应于相同键k的值,则可以调用op而不将结果添加到映射中。
*我已经手动检查了2.11.7,仍然"至少一次"
如何保证一次性通话(如果我为工厂使用TrieMap)?
答案 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
方法,我也可以使用它。