实践中的Java Concurrency说你可以通过将它粘贴到如下所示的同步集合中来安全地发布一个有效的不可变对象(比如,你构造的Date对象并且永远不会再改变)(来自书籍,第53页): / p>
public Map<String, Date> lastLogin =
Collections.synchronizedMap(new HashMap<String, Date>())
据我所知,放入此映射的任何Date对象一旦置于此同步映射中,将可见(至少在其初始但完全构造的状态),但只有一次其他线程可以获取对此Map对象的引用。
由于引用字段lastLogin没有保证可见性的字段属性(最终,易失性,保护或静态初始化程序初始化),我认为地图本身可能不会以完全构造的状态显示到其他线程,因此把车放在马前。或者我错过了什么?
答案 0 :(得分:5)
您的怀疑是正确的,因为lastLogin
的值不能保证对其他线程可见。由于lastLogin
不是volatile
或final
,因此另一个帖子可能会将其视为null
。
但是,您不必担心其他线程会看到地图的不完整版本。 Collections.synchronizedMap(...)
会返回a private class个final
个字段的实例。 JLS section 17.5说:
最终字段的使用模型很简单:在该对象的构造函数中设置对象的最终字段;并且在对象的构造函数完成之前,不要在另一个线程可以看到的地方写入对正在构造的对象的引用。如果遵循这一点,那么当另一个线程看到该对象时,该线程将始终看到该对象的最终字段的正确构造版本。
SynchronizedMap
遵循这些规则,因此另一个阅读lastLogin
的帖子将会读取null
或对完全构建的地图的引用,而不会引用地图的不完整或不安全版本