Java 并发:“级联”中的 Volatile 与 Final变量?

发布于 2024-09-04 09:21:09 字数 1138 浏览 9 评论 0原文

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

与内部 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);

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

坦克! 汤姆

is

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

the same as

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

in case the inner Map is accessed by different Threads?

or is even something like this required:

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

In case the it is NOT a "cascaded" map, final and volatile have in the end the same effect of making shure that all threads see always the correct contents of the Map... But what happens if the Map iteself contains a map, as in the example... How do I make shure that the inner Map is correctly "Memory barriered"?

Tanks!
Tom

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

南城旧梦 2024-09-11 09:21:09

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

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

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

检索操作(包括get)
一般不会阻塞,所以可能会重叠
具有更新操作(包括 put
并删除)。检索结果反映了
最近完成的结果
更新操作持有其
发病。

这种措辞有点奇怪,但要点是,任何在某个 put 操作返回之后开始的 get 操作都保证能看到结果那把。所以你甚至不需要在外部地图上使用易失性; JLS 说道:

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

总结

外部地图上的 final 就足够了。

volatile only affects the ability of other threads to read the value of the variables it's attached to. It in no way affects the ability of another thread to see the keys and values of the map. For instance, I could have a volatile int[]. If I change the reference—i.e. if I change the actual array that it points to—other threads reading the array are guaranteed to see that change. However, if I change the third element of the array no such guarantees are made.

If status is final, the construction of the containing class creates a happens-before relationship with any subsequent reads, so they are able to see the value of status. Likewise any reads to your volatile variable are guaranteed to see the latest reference assignment to it. It's unlike you're swapping the actual map around very often, more like you're just changing keys and the overall map object stays as is.

For this question, then, we need to consult the documentation for ConcurrentHashMap:

Retrieval operations (including get)
generally do not block, so may overlap
with update operations (including put
and remove). Retrievals reflect the
results of the most recently completed
update operations holding upon their
onset.

This is kind of oddly worded, but the gist is that any get operation whose onset is after some put operation's return is guaranteed to see the results of that put. So you don't even need a volatile on the outer map; quoth the JLS:

A thread that can only see a reference
to an object after that object has
been completely initialized is
guaranteed to see the correctly
initialized values for that object's
final fields.

Summary

A final on the outer map is sufficient.

两仪 2024-09-11 09:21:09

Google 集合值得一看,尤其是MapMaker 可让您智能地设置和创建地图。能够设置弱值,以实现更好的垃圾收集和过期时间,以便您可以使用映射进行有效的缓存,这真是太棒了。由于 MapMaker 制作的 Map (: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 的定义,因为它看起来不正确。

It's worth looking at Google-Collections and, in particular, MapMaker that lets you intelligently setup and create Maps. Being able to setup weak values, to enable better garbage collection, and expiration times, so you can use Maps for effective caching, is brilliant. As the Maps that MapMaker makes (:p) have the same properties as ConcurrentHashMap, you can be happy with its thread-safety.

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

Please note, you might want to look at your definition of statusInner, as it doesn't seem right.

煮茶煮酒煮时光 2024-09-11 09:21:09

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

使用 ConcurrentHashMap 几乎就是您所需要的。是的,如果可以的话,请引用顶级 Map final,但在任何情况下都不需要 volatile。内部的第二级 Map 引用是 ConcurrentHashMap 的职责,人们认为它是正确的。

I think the best answer here is that volatile is not a way to ensure thread-safety.

Using ConcurrentHashMap is pretty much all you need. Yes, make the reference to the top-level Map final if you can, but volatile is not necessary in any event. The second-level Map reference inside are the business of ConcurrentHashMap to get right, and one assumes it does.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文