为什么 ConcurrentHashMap 在 Double Checked Locking 中工作
Why does ConcurrentHashMap work in Double Checked Locking
在书中 "Java Concurrency in Practice" 提到以下代码不是线程安全的:
@NotThreadSafe
public class DoubleCheckedLocking {
private static Resource resource;
public static Resource getInstance(){
if(resource == null){
synchronized (DoubleCheckedLocking.class){
if(resource == null)
resource = new Resource();
}
}
return resource;
}
}
它不是线程安全的,因为:
- 一个线程可以创建新的资源实例
- 在"if" 条件下同时另一个线程可以得到非空引用但Resource 的对象将不会被完全初始化
在此question中是类似的代码。资源存储在 concurentHashMap 中,人们说它是线程安全的。像这样:
public class DoubleCheckedLocking2 {
private static ConcurrentHashMap<String, ComplexObject> cache = new ConcurrentHashMap<String, ComplexObject>();
public static ComplexObject getInstance(String key) {
ComplexObject result = cache.get(key);
if (result == null) {
synchronized (DoubleCheckedLocking2.class) {
ComplexObject currentValue = cache.get(key);
if (currentValue == null) {
result = new ComplexObject();
cache.put(key, result);
} else {
result = currentValue;
}
}
}
return result;
}
}
为什么将值存储在 ConcurrentHashMap 中使代码线程安全?我认为 ComplexObject 仍然有可能不会被完全初始化并且这个 "partial object" 将被保存在地图中。其他线程将读取部分未完全初始化的对象。
我想我知道什么是"happens-before",我已经分析了JDK8.0_31中的代码,但我仍然不知道答案。
我知道 computeIfAbsent、putIfAbsent 等函数。我知道这段代码可以用不同的方式编写。我只是想知道使这段代码线程安全的细节。
Happens before其实是这里的关键。 happens before 边缘从 map.put(key, object)
延伸到后续的 map.get(key)
,因此您检索的对象至少与当时的对象一样最新已存储在地图中。
在书中 "Java Concurrency in Practice" 提到以下代码不是线程安全的:
@NotThreadSafe
public class DoubleCheckedLocking {
private static Resource resource;
public static Resource getInstance(){
if(resource == null){
synchronized (DoubleCheckedLocking.class){
if(resource == null)
resource = new Resource();
}
}
return resource;
}
}
它不是线程安全的,因为: - 一个线程可以创建新的资源实例 - 在"if" 条件下同时另一个线程可以得到非空引用但Resource 的对象将不会被完全初始化
在此question中是类似的代码。资源存储在 concurentHashMap 中,人们说它是线程安全的。像这样:
public class DoubleCheckedLocking2 {
private static ConcurrentHashMap<String, ComplexObject> cache = new ConcurrentHashMap<String, ComplexObject>();
public static ComplexObject getInstance(String key) {
ComplexObject result = cache.get(key);
if (result == null) {
synchronized (DoubleCheckedLocking2.class) {
ComplexObject currentValue = cache.get(key);
if (currentValue == null) {
result = new ComplexObject();
cache.put(key, result);
} else {
result = currentValue;
}
}
}
return result;
}
}
为什么将值存储在 ConcurrentHashMap 中使代码线程安全?我认为 ComplexObject 仍然有可能不会被完全初始化并且这个 "partial object" 将被保存在地图中。其他线程将读取部分未完全初始化的对象。
我想我知道什么是"happens-before",我已经分析了JDK8.0_31中的代码,但我仍然不知道答案。
我知道 computeIfAbsent、putIfAbsent 等函数。我知道这段代码可以用不同的方式编写。我只是想知道使这段代码线程安全的细节。
Happens before其实是这里的关键。 happens before 边缘从 map.put(key, object)
延伸到后续的 map.get(key)
,因此您检索的对象至少与当时的对象一样最新已存储在地图中。