這是本文件的舊版!


Synchronized with String intern

下面程式碼是相當常見的lazy-instantiation。但在多執行緒存取時,會針對某一相同的key產生多個不同instance。也許最後在map中僅存著一份instance,但如果CreateCache動作耗時或有其它沒預料到的side-effect呢?

private volatile Map<String, Object> mCacheMap= new ConcurrentHashMap<String, Object>();
 
public Object getCache(String key){
	if(!mCacheMap.contains(key)){
		mCacheMap.put(key, createCache(key));
	}
	return mCacheMap.get(key);
}
最常見的做法是在method上增加synchronized,
public synchronized  Object getCache(String key){
  // ...
}
或在method內增加synchronized block,
public Object getCache(String key){
	synchronized(mCacheMap){
		// ...
	}
}
上面兩種方式,都屬於不管怎樣就是做同步的控管。但我們只需要針對key相同的情形做控管,才能獲得比較好的效能。

所以我們“也許”可以寫成這樣:

public Object getCache(String key){
	synchronized(key.intern()){
		// ...
	}
}
但對沒使用過的東西,我無法放100萬個心下來,所以稍微google了這method的資訊。赫然發現,許多的人都不推使用String intern()。觀看intern裡面的實做,最後會呼叫到JVM的native code,因此這實做是綁在JVM上的。