Scala中如何无var从ConcurrentHashMap安全获取新旧值?
不用null初始化的var获取ConcurrentHashMap的新旧值
可以实现,核心是借助可变容器在compute的原子操作内保存旧值,避免使用null初始化的var。因为compute方法的执行是原子性的(持有对应key的锁执行整个lambda逻辑),所以容器的读写不会有线程安全问题。
方案1:用Array作为值容器
Array是Scala中自带的可变容器,适合用来临时存储单个值:
import java.util.concurrent.ConcurrentHashMap val map: ConcurrentHashMap[String, Object] = new ConcurrentHashMap[String, Object]() // 假设这是你的初始值 val initialValue = new Object() // 生成新值的逻辑 def setNewValue(prev: Object): Object = { new Object() // 替换成你的实际逻辑 } def foo = { // 用长度为1的数组存储旧值 val prevHolder = new Array[Object](1) val newValue = map.compute("key", (_, value) => { prevHolder(0) = Option(value).getOrElse(initialValue) setNewValue(prevHolder(0)) }) // 返回旧值和新值的元组 (prevHolder(0), newValue) }
方案2:用AtomicReference(语义更清晰)
如果想明确表达“可变引用”的意图,可以用Java的AtomicReference:
import java.util.concurrent.{ConcurrentHashMap, AtomicReference} val map: ConcurrentHashMap[String, Object] = new ConcurrentHashMap[String, Object]() val initialValue = new Object() def setNewValue(prev: Object): Object = { new Object() } def foo = { val prevRef = new AtomicReference[Object]() val newValue = map.compute("key", (_, value) => { val prev = Option(value).getOrElse(initialValue) prevRef.set(prev) setNewValue(prev) }) (prevRef.get(), newValue) }
原理说明
ConcurrentHashMap.compute方法会原子性执行传入的lambda:在持有当前key的独占锁前提下,先获取旧值、执行计算逻辑、再更新新值。因此lambda内部对容器的修改是线程安全的,外部在compute执行完成后读取容器,得到的一定是正确的旧值,同时compute的返回值就是新值,完美实现需求。
内容的提问来源于stack exchange,提问作者marcin
相关产品推荐
相关产品推荐

