Map<String, Locale> map = new HashMap<String,Locale>(); java
在單線程環境下能夠知足要求,可是在多線程環境下會存在線程安全性問題,即不能保證在併發的狀況相同的 key 返回同一個 Local 對象引用。安全
這是由於在上面的代碼裏存在一個習慣被稱爲 put-if-absent 的操做 [1],而這個操做存在一個 race condition:多線程
由於在某個線程作完 locale == null 的判斷到真正向 map 裏面 put 值這段時間,其餘線程可能已經往 map 作了 put 操做,這樣再作 put 操做時,同一個 key 對應的 locale 對象被覆蓋掉,最終 getInstance 方法返回的同一個 key 的 locale 引用就會出現不一致的情形。因此對 Map 的 put-if-absent 操做是不安全的(thread safty)。併發
爲了解決這個問題,java 5.0 引入了 ConcurrentMap 接口,在這個接口裏面 put-if-absent 操做以原子性方法 putIfAbsent(K key, V value) 的形式存在。app
因此能夠使用該方法替代上面代碼裏的操做。可是,替代的時候很容易犯一個錯誤。請看下面的代碼:spa
這段代碼使用了 Map 的 concurrent 形式(ConcurrentMap、ConcurrentHashMap),並簡單的使用了語句map.putIfAbsent(key, locale) 。這一樣不能保證相同的 key 返回同一個 Locale 對象引用。線程
這裏的錯誤出在忽視了 putIfAbsent 方法是有返回值的,而且返回值很重要對象
「若是(調用該方法時)key-value 已經存在,則返回那個 value 值。若是調用時 map 裏沒有找到 key 的 mapping,返回一個 null 值」接口
因此,使用 putIfAbsent 方法時切記要對返回值進行判斷,增長了對方法返回值的判斷:get
這樣能夠保證併發狀況下代碼行爲的準確性。