7

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);

一样

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);

如果内部地图被不同的线程访问?

或者甚至需要这样的东西:

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);

如果它不是“级联”映射,最终和 volatile 最终具有相同的效果,即所有线程始终看到映射的正确内容......但是如果映射本身包含映射会发生什么,如示例中所示...如何确保内部 Map 正确“内存屏障”?

坦克!汤姆

4

3 回答 3

10

volatile只会影响其他线程读取它所附加的变量值的能力。它绝不会影响另一个线程查看映射的键和值的能力。例如,我可以有一个volatile int[]. 如果我更改引用——即如果我更改它指向的实际数组——其他读取该数组的线程保证会看到该更改。但是,如果我更改数组的第三个元素,则不会做出此类保证。

如果statusfinal,包含类的构造会happens-before与任何后续读取建立关系,因此它们能够看到状态的值。volatile同样,保证对变量的任何读取都可以看到对其的最新引用分配。这与您经常交换实际地图不同,更像是您只是在更改键并且整个地图对象保持原样。

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

检索操作(包括 get)一般不会阻塞,因此可能与更新操作(包括 put 和 remove)重叠。检索反映了最近完成的更新操作在其开始时保持的结果。

这是一种奇怪的措辞,但要点是,任何在某个操作返回之后get开始的操作都可以保证看到该 put 的结果。所以你甚至不需要外层地图上的 a ;引用 JLS:putvolatile

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

概括

final外地图上的一个就足够了。

于 2010-06-03T08:19:30.160 回答
4

值得一看的是Google-Collections,尤其是MapMaker,它可以让您智能地设置和创建地图。能够设置弱值,以实现更好的垃圾收集和过期时间,因此您可以使用 Maps 进行有效缓存,这非常棒。由于 MapMaker 制作的地图 (:p) 具有与 ConcurrentHashMap 相同的属性,因此您可以对其线程安全感到满意。

final mapMaker = new MapMaker().weakValues(); //for convenience, assign
final Map<Integer,Map<String,Integer>> status = mapMaker.makeMap();
status.put(key, mapMaker.<String, Integer>makeMap());

请注意,您可能想查看您对 statusInner 的定义,因为它看起来不正确。

于 2010-06-03T08:23:54.630 回答
1

我认为这里最好的答案是这volatile不是确保线程安全的方法。

使用ConcurrentHashMap几乎是您所需要的。Map final是的,如果可以的话,请参考顶层,但volatile无论如何都没有必要。里面的二级Map参考是ConcurrentHashMap正确的业务,并且假设它确实如此。

于 2010-06-03T08:10:37.377 回答