线程安全地更新Scala集合 [英] Updating Scala collections thread-safely
问题描述
我想知道是否有任何简单的方法来安全地更新不可变的scala集合。考虑下面的代码:
class a {
private var x = Map [Int,Int]()
def update(p:(Int,Int)){x = x +(p)}
}
这段代码不是线程安全的,正确吗?我的意思是,如果我们有两个线程调用update方法,让我们说x是map包含{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}。有一个简单的方法来解决这个问题吗?我希望它是undestandable我要求:)
Btw,我知道有解决方案像Akka STM,但我宁愿不使用那些,除非必要。非常感谢任何答案!
编辑:此外,我宁愿解决方案没有锁定。 Eeeew:)
在你的情况下,正如Maurício写的,你的集合已经是线程安全的,因为它是不可变的。唯一的问题是重新分配 var
,这可能不是原子操作。对于这个特定的问题,最简单的选择是使用 java.util.concurrent.atomic
中的nice类,即 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 //获取旧值
val newMap = oldMap + p //更新
if(x.compareAndSet(oldMap,newMap))
return // exit if update已成功,否则重复
}
}
}
i was wondering if there is any 'easy' way to update immutable scala collections safely. Consider following code:
class a {
private var x = Map[Int,Int]()
def update(p:(Int,Int)) { x = x + (p) }
}
This code is not thread safe, correct? By that i mean that if we have two threads invoking update method and lets say that x is map containing { 1=>2 } and thread A invokes update((3,4)) and only manages to execute the x + (p) part of the code. Then rescheduling occurs and thread B invokes update((13,37)) and successfully updates the variable x. The thread A continues and finishes.
After all this finishes, value x would equal map containing { 1=>2, 3=>4 }, correct? Instead of desired { 1=>2, 3=>4, 13=>37 }. Is there a simple way to fix that? I hope it's undestandable what I'm asking :)
Btw, i know there are solutions like Akka STM but i would prefer not to use those, unless necessary.
Thanks a lot for any answer!
edit: Also, i would prefer solution without locking. Eeeew :)
In your case, as Maurício wrote, your collection is already thread safe because it is immutable. The only problem is reassigning the var
, which may not be an atomic operation. For this particular problem, the easiest option is to use of the nice classes in java.util.concurrent.atomic
, namely 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
}
}
}
这篇关于线程安全地更新Scala集合的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!