Java并发:"级联"变量中的易失性与最终性?

Tom*_*Tom 6 java concurrency final volatile concurrenthashmap

final Map<Integer,Map<String,Integer>> status = new ConcurrentHashMap<Integer, Map<String,Integer>>();
Map<Integer,Map<String,Integer>> statusInner = new ConcurrentHashMap<Integer, Map<String,Integer>>();
status.put(key,statusInner);
Run Code Online (Sandbox Code Playgroud)

同样的

volatile Map<Integer,Map<String,Integer>> status = new ConcurrentHashMap<Integer,   Map<String,Integer>>();
Map<Integer,Map<String,Integer>> statusInner = new ConcurrentHashMap<Integer, Map<String,Integer>>();
status.put(key,statusInner);
Run Code Online (Sandbox Code Playgroud)

如果内部Map由不同的线程访问?

或者甚至是这样的要求:

volatile Map<Integer,Map<String,Integer>> status = new ConcurrentHashMap<Integer, Map<String,Integer>>();
volatile Map<Integer,Map<String,Integer>> statusInner = new ConcurrentHashMap<Integer, Map<String,Integer>>();
status.put(key,statusInner);
Run Code Online (Sandbox Code Playgroud)

如果它不是一个"级联"地图,那么final和volatile最终会产生同样的效果,即所有线程总是看到Map的正确内容......但是如果Map iteself包含一个map,会发生什么?在示例中...如何使内部地图正确"内存瘫痪"?

坦克!汤姆

jas*_*p85 9

volatile仅影响其他线程读取其附加的变量值的能力.它决不会影响另一个线程查看地图的键和值的能力.例如,我可以有一个volatile int[].如果我更改引用 - 即如果我更改它指向的实际数组 - 其他线程读取数组保证看到该更改.但是,如果我更改数组的第三个元素,则不会进行此类保证.

如果statusfinal,则包含类的构造happens-before与任何后续读取创建关系,因此它们能够看到状态的值.同样,对volatile变量的任何读取都保证会看到对它的最新引用赋值.这与你经常交换实际地图不同,更像是你只是改变键而整个地图对象保持不变.

对于这个问题,我们需要查阅以下文档ConcurrentHashMap:

检索操作(包括get)通常不会阻塞,因此可能与更新操作(包括put和remove)重叠.检索反映了最近完成的更新操作的结果.

这是一种奇怪的措辞,但要点是任何get操作的开始是一些put操作返回之后保证看到该放置的结果.所以你甚至不需要volatile在外图上; JLS:

在该对象完全初始化之后只能看到对象引用的线程可以保证看到该对象的最终字段的正确初始化值.

摘要

final外部地图上的A 就足够了.