3

这似乎是错误的。

        static ConcurrentHashMap k; //multiple threads have access to k
         X o = k.get("LL");
         o.a = 6;

如果多个线程同时访问 k,并获取 k("LL"),那么 update (oa = #) 没有 k.put("ll",o),没有在 'o' 上同步,或者在 'k' 上会发生什么?

4

3 回答 3

2

ConcurrentHashMap 保证获取值是原子的,但它无法控制您对从中获取的值执行的操作。从 ConcurrentHashMap 的角度来看,修改 hashmap 中的值很好,但可能仍然不会产生您想要的行为。为了确保线程安全,您需要准确考虑每个有权访问它的线程的作用。

将值放回 ConcurrentHashMap 似乎是多余的,并且不会使整个操作更安全。您已经在任何同步之外修改对象。

可能需要额外的同步,但如果没有更多上下文,我无法确定。

于 2012-11-04T02:16:59.650 回答
2

ConcurrentMap 具有保证原子插入/删除和替换键/值对的条件操作。此外,访问 ConcurrentMap 会创建发生前的关系,因此您可以对代码的顺序做出某些保证。

在呈现的代码中,该行:

X o = k.get("LL");

访问键“LL”的当前 X 值。下一行修改 a 属性。在不知道 X 的实现的情况下,这是 Java,所以我们知道这里没有方法调用。如果(且仅当)a 属性被标记为 volatile,那么在“LL”处访问 X 的一些后续代码会将 a 值视为 6。如果它不是 volatile,则根本无法保证。他们可能会看到 6,尤其是在 SMP x86 机器上,当时没有多少线程在做很多事情。在生产中,在一个大的 NUMA 盒子上,它们不太可能。可变性带来了各种复杂和困难。

通常,如果您使用不可变的键和值,您会发现更容易推断地图的状态。

于 2012-11-05T01:06:57.010 回答
1

简单来说:

  o.a=6

是原子操作,所有线程都将竞争,最后一个线程设置它将“获胜”,覆盖该值。

更具体地说,ConcurrentHashMap 只保证键与其关联值之间的链接在处理时会考虑多个线程——即put 和 get 是原子的

这不会阻止任何线程在获得对它的引用后修改该值的属性!

于 2012-11-04T01:44:33.853 回答