不可变对象场景下Volatile的必要性及线程安全疑问
关于Java中volatile关键字的必要性分析
先贴出你的代码(补全了语法细节):
private volatile MultiMap myMap; public void doProcessing() { myMap = getValueFromMainThread(); myForkJoinPool.submit(() -> readWithinMultipleThreads()); } private void readWithinMultipleThreads() { readSomethingFrom(myMap.get(...)); }
你的判断有一半是对的,但volatile关键字绝对不能去掉,原因如下:
核心问题是引用的可见性,而非容器内部线程安全
你提到子线程只读取myMap的状态不修改,这点没错——如果getValueFromMainThread()返回的MultiMap实例,在被提交的子线程读取期间,不会被任何线程(包括主线程)修改内部状态,那这个MultiMap确实不需要具备线程安全性。但这里的关键是myMap这个引用本身:主线程对它的赋值操作,需要确保能被所有子线程立刻看到。没有volatile会导致内存可见性问题
按照Java内存模型的规则,主线程对非volatile变量的写入,不会强制刷新到主内存;子线程可能会从自己的CPU缓存中读取myMap的旧值(比如初始的null),从而导致调用myMap.get()时抛出空指针,或者操作的是过期的MultiMap实例。volatile的作用恰好匹配这个场景
volatile关键字的核心作用就是保证变量的可见性:当主线程修改了myMap的引用后,所有子线程后续读取到的都会是最新的引用值,不会出现缓存不一致的问题。
总结:
MultiMap实例本身不需要线程安全(只要全程只读)myMap这个引用必须保留volatile修饰,否则会出现线程间的内存可见性问题
内容的提问来源于stack exchange,提问作者HamoriZ
相关产品推荐
相关产品推荐

