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/