【问题标题】:Will a ConcurrentHashMap ever expose a partially constructed object via get()?ConcurrentHashMap 是否会通过 get() 公开部分构造的对象?
【发布时间】:2018-01-29 15:57:35
【问题描述】:

JavaDoc for ConcurrentHashMap states:

检索操作(包括 get)一般不会阻塞,因此可能与更新操作(包括 put 和 remove)重叠。检索反映了最近完成的更新操作在其开始时保持的结果。 (更正式地说,给定键的更新操作与报告更新值的键的任何(非空)检索具有发生前的关系。)

由于“对给定键的更新操作...发生之前...对该键的任何(非空)检索”并且部分构造的对象被认为是非空的,*以下代码是否可能允许Thread2 访问部分构造的对象?

Thread1:

// Immutable Object (all fields final)
concurrentHashMap.put("immutableObject", new ImmutableObject());

// Volatile Object (all fields volatile)
concurrentHashMap.put("volatileObject", new VolatileObject());

// Thread-safe Mutable Object
concurrentHashMap.put("mutableObject", new MutableObject());

Thread2:

concurrentHashMap.get("immutableObject");
concurrentHashMap.get("volatileObject");
concurrentHashMap.get("mutableObject");

是否需要在这些对象的构造函数中执行某种同步,以确保在它们完全初始化之前没有线程访问它们?

* 我不能 100% 确定部分构造的对象被认为是非空的,但我没有看到任何相反的证据。似乎由于线程可以访问部分初始化的对象,部分初始化的对象不能为空,因为某些内部数据(无论是初始化的)是可访问的。

【问题讨论】:

标签: java concurrency concurrenthashmap


【解决方案1】:

在您的示例中,您永远不会将部分构造的对象添加到地图中。
参数在传递给方法之前进行评估。

15.12.4. Run-Time Evaluation of Method Invocation JLS 确实声明参数表达式(第二步)在方法执行(最后一步)之前进行评估:

在运行时,方法调用需要五个步骤。首先,一个目标 可以计算参考。 第二,参数表达式为 评估。三、被调用方法的可访问性是 检查。四、要执行的方法的实际代码是 位于。 五、创建新的激活帧,同步是 必要时执行,并将控制转移到方法代码

所以这里:

concurrentHashMap.put("immutableObject", new ImmutableObject());

new ImmutableObject() 被评估,ImmutableObject 对象在传递给concurrentHashMap.put(..) 方法之前完全构建。

【讨论】:

【解决方案2】:

put 的调用将每次阻塞,直到每个构造函数完成,从而使 put 操作原子化。

因此,如果get 调用与put 调用不连续,它们可能会在键值对已经存在时查询映射,也可能不查询并产生null

这是一个永远运行的最小示例,用于说明:

Map<String, Foo> map = new ConcurrentHashMap<>();
map.put("", new Foo());

class Foo {
    Foo() {
        while (true) {}
    }
}

【讨论】:

  • +1 这个例子对我很有帮助,我创建了一个线程,将Foo 放在地图中,另一个线程试图一遍又一遍地获取它。第二个线程永远不会检索部分构造的对象。相反,它总是会得到null
  • @stiemannkj1 正是如此。由于构造函数永远不会完成它的工作,put 操作永远不会成功,任何get 调用都将为该键返回null(假设该键不存在,也就是说)。
【解决方案3】:
concurrentHashMap.put("immutableObject", new ImmutableObject());

这一行按以下顺序做了两件事:

  1. 创建一个新的 ImmutableObject
  2. 将创建的对象添加到 hashmap 中

所以答案是否定的,hashmap 不能返回部分构造的对象,因为对象在添加到 hashmap 之前就已经完全构造好了。

【讨论】:

    猜你喜欢
    • 2021-06-29
    • 2012-08-14
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-02-01
    • 1970-01-01
    • 1970-01-01
    • 2015-01-23
    相关资源
    最近更新 更多