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%确定部分构造的对象被认为是非空的,但是我还没有看到相反的证据。似乎因为线程可以访问部分初始化的对象,所以部分访问的内部数据(无论初始化了什么)都可以访问,因此部分初始化的对象不能为null。

最佳答案

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

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


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


所以在这里 :

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


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

关于java - ConcurrentHashMap是否会通过get()公开部分构造的对象?,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/45799421/

10-11 06:47
查看更多