最近在學習Hystrix框架時,看到有一段代碼,挺有意思的,代碼如下:
代碼清單1-1
public class InternMap<K, V> {
private final ConcurrentMap<K, V> storage = new ConcurrentHashMap<K, V>();
private final ValueConstructor<K, V> valueConstructor;
public interface ValueConstructor<K, V> {
V create(K key);
}
public V interned(K key) {
V existingKey = storage.get(key);
V newKey = null;
if (existingKey == null) {
newKey = valueConstructor.create(key);
existingKey = storage.putIfAbsent(key, newKey);
}
return existingKey != null ? existingKey : newKey;
}
}
省略了部分非關注代碼……
ValueConstructor是函數式接口,作用是傳入key獲得value值,JDK8引入的新特性。
重點關注上面的interned方法:先是判斷key對應的value是否已存在:如果不存在,則通過ValueConstructor產生新的value,並存入storage中。最後返回已存在的value
邏輯很簡單,但是上面的代碼卻寫得很複雜,感覺有點囉嗦,一般寫法如下:
代碼清單1-2
public V interned(K key) {
V existingValue = storage.get(key);
if (existingValue == null) {
existingValue = valueConstructor.create(key);
storage.put(key, existingValue);
}
return existingValue;
}
仔細分析下上面簡單寫法,存在着線程安全問題。由於未進行同步處理,可能出現兩個線程同時進入if語句塊,從而導致每個線程獲得了不同的existingValue,這顯然是不希望看到的。
再回過頭來看代碼1-1,就明白作者的深意了。通過ConcurrentHashMap提供的線程安全的putIfAbsent方法,保證了storage存入時的線程安全,同時通過對newKey、existingKey(實際上應該取名爲newValue、existingVaule)兩個線程內變量值判斷進行返回,保證了整個方法操作的原子性。
這種實現線程安全的方式,沒有用同步代碼塊等比較低效的同步方式,確實是一種高效實現Map的原子更新方式,不得不爲作者的深思熟慮感到佩服.......
最後,我想問句:元芳,你怎麼看?