Java多线程原子引用赋值

Sha*_*mik 18 java multithreading

我有一个缓存,我使用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块将负责排序和可见性?

sjl*_*lee 27

它是不是安全的没有一个适当的内存屏障.

有人会认为在填充缓存的步骤之后会发生缓存(cache = newCache)的分配.但是,其他线程可能会遭受这些语句的重新排序,因此分配可能在填充缓存之前发生.因此,可以在完全构造之前获取新缓存,甚至可以看到ConcurrentModificationException.

您需要强制执行before-before关系以防止此重新排序,并将缓存声明为volatile将实现此目的.

  • 很好的答案,但我只想添加一些必读内容:http://www.cs.umd.edu/~pugh/java/memoryModel/ (2认同)