Arg*_*Arg 19 collections concurrency scala thread-safety
我想知道是否有任何'简单'的方法来安全地更新不可变的scala集合.考虑以下代码:
class a {
private var x = Map[Int,Int]()
def update(p:(Int,Int)) { x = x + (p) }
}
Run Code Online (Sandbox Code Playgroud)
这段代码不是线程安全的,对吗?我的意思是,如果我们有两个线程调用update方法,并且假设x是包含{1 => 2}的映射,并且线程A调用update((3,4))并且只设法执行x +(p)部分代码.然后重新安排,线程B调用update((13,37))并成功更新变量x.线程A继续并结束.
完成所有这些后,值x将等于包含{1 => 2,3 => 4}的地图,对吗?而不是期望的{1 => 2,3 => 4,13 => 37}.有没有一种简单的方法来解决这个问题?我希望我的要求是不可靠的:)
顺便说一句,我知道有像Akka STM这样的解决方案,但除非必要,否则我宁愿不使用它们.
非常感谢您的回答!
编辑:另外,我更喜欢没有锁定的解决方案.Eeeew :)
Jea*_*let 20
在你的情况下,正如Maurício所写,你的集合已经是线程安全的,因为它是不可变的.唯一的问题是重新分配var,这可能不是原子操作.对于这个特殊问题,最简单的选择是使用好的类java.util.concurrent.atomic,即AtomicReference.
import java.util.concurrent.atomic.AtomicReference
class a {
private val x = new AtomicReference(Map[Int,Int]())
def update(p:(Int,Int)) {
while (true) {
val oldMap = x.get // get old value
val newMap = oldMap + p // update
if (x.compareAndSet(oldMap, newMap))
return // exit if update was successful, else repeat
}
}
}
Run Code Online (Sandbox Code Playgroud)
集合本身是线程安全的,因为它没有共享可变状态,但您的代码不是,并且没有办法在不锁定的情况下修复此问题,因为您确实具有共享可变状态。最好的选择是锁定方法本身,将其标记为同步。
另一个解决方案是使用可变并发映射,可能是java.util.concurrent.ConcurrentMap。
| 归档时间: |
|
| 查看次数: |
7346 次 |
| 最近记录: |