Java 为什么ConcurrentHashMap在双重检查锁定中工作
在《实践中的Java并发》一书中提到,以下代码不是线程安全的:Java 为什么ConcurrentHashMap在双重检查锁定中工作,java,multithreading,double-checked-locking,Java,Multithreading,Double Checked Locking,在《实践中的Java并发》一书中提到,以下代码不是线程安全的: @NotThreadSafe 公共类双重检查锁定{ 私有静态资源; 公共静态资源getInstance(){ if(资源==null){ 已同步(DoubleCheckedLocking.class){ if(资源==null) 资源=新资源(); } } 返回资源; } } 它不是线程安全的,因为: -一个线程可以创建资源的新实例 -同时处于“if”条件的另一个线程可以获得not empty引用,但资源的对象将不会完全初始化 这
@NotThreadSafe
公共类双重检查锁定{
私有静态资源;
公共静态资源getInstance(){
if(资源==null){
已同步(DoubleCheckedLocking.class){
if(资源==null)
资源=新资源();
}
}
返回资源;
}
}
它不是线程安全的,因为:
-一个线程可以创建资源的新实例
-同时处于“if”条件的另一个线程可以获得not empty引用,但资源的对象将不会完全初始化
这是类似的代码。资源存储在ConcurrenthashMap中,人们说它是线程安全的。大概是这样的:
公共类双重检查锁定2{
私有静态ConcurrentHashMap缓存=新ConcurrentHashMap();
公共静态ComplexObject getInstance(字符串键){
ComplexObject结果=cache.get(key);
如果(结果==null){
已同步(双重检查锁定2.class){
ComplexObject currentValue=cache.get(键);
if(currentValue==null){
结果=新的ComplexObject();
cache.put(键、结果);
}否则{
结果=当前值;
}
}
}
返回结果;
}
}
为什么将值存储在ConcurrentHashMap中会使代码线程安全?我认为ComplexObject仍有可能无法完全初始化,而这个“部分对象”将保存在映射中。其他线程将读取部分未完全初始化的对象
我想我知道“以前发生过什么”,我已经分析了JDK 8.0_31中的代码,但我仍然不知道答案
我知道ComputeFabSent、putIfAbsent等函数。我知道这段代码可以用不同的方式编写。我只是不知道使这段代码线程安全的细节。之前发生的事情实际上是这里的关键。从
map.put(key,object)
到后续的map.get(key)
,有一个before-before-edge扩展,因此您检索的对象至少与存储在映射中时一样是最新的。因此我们不能保证映射中存储的ComplexObject的实例将被完全初始化。put操作后,其他线程是否可能获得未完全初始化的ComplexObject的引用?如果是,则它不是线程安全的。我的回答意味着它是线程安全的,因为它是在边缘之前发生的。写入线程在放入映射之前所做的一切都保证在读取线程获取对象后被读取线程观察到。这就是“先发生后发生”关系及物性的本质。也许你错过了在节目结束前发生的事情?