我想知道是否有任何'简单'的方法来安全地更新不可变的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 :)
我有一个缓存,我使用simeple HashMap实现.喜欢 -
HashMap<String,String> cache = new HashMap<String,String>();
Run Code Online (Sandbox Code Playgroud)
大多数时候使用此缓存来从中读取值.我有另一个方法重新加载缓存,在这个方法内部我基本上创建一个新的缓存,然后分配引用.据我所知,对象引用的赋值是Java中的Atomic.
public class myClass {
private HashMap<String,String> cache = null;
public void init() {
refreshCache();
}
// this method can be called occasionally to update the cache.
public void refreshCache() {
HashMap<String,String> newcache = new HashMap<String,String>();
// code to fill up the new cache
// and then finally
cache = newcache; //assign the old cache to the new one in Atomic way
}
}
Run Code Online (Sandbox Code Playgroud)
我理解如果我不将缓存声明为volatile,其他线程将无法看到更改,但对于我的用例将缓存中的更改传播到其他线程并且它们可以继续使用旧缓存并不是时间关键延长时间.
你看到任何线程问题吗?考虑到许多线程正在从缓存中读取,并且有时只重新加载缓存.
编辑 - 我的主要困惑是我不必在这里使用AtomicReference,因为赋值操作本身是原子的?
编辑 - 我理解为了使顺序正确,我应该将缓存标记为volatile.但是如果refreshCache方法被标记为synchronized,我不必将缓存设置为volatile,因为Synchronized块将负责排序和可见性?