HashMap不是線程安全的
ConcurrentHashMap是線程安全的
從JDK1.2起,就有了HashMap,正如前一篇文章所說,HashMap不是線程安全的,因此多線程操作時需要格外小心。
在JDK1.5中,偉大的Doug Lea給我們帶來了concurrent包,從此Map也有安全的了。
ConcurrentHashMap具體是怎么實現線程安全的呢,肯定不可能是每個方法加synchronized,那樣就變成了HashTable。
從ConcurrentHashMap代碼中可以看出,它引入了一個“分段鎖”的概念,具體可以理解為把一個大的Map拆分成N個小的HashTable,根據key.hashCode()來決定把key放到哪個HashTable中。
在ConcurrentHashMap中,就是把Map分成了N個Segment,put和get的時候,都是現根據key.hashCode()算出放到哪個Segment中:
測試程序:
import java.util.concurrent.ConcurrentHashMap; public class ConcurrentHashMapTest { private static ConcurrentHashMap<Integer, Integer> map = new ConcurrentHashMap<Integer, Integer>(); public static void main(String[] args) { new Thread("Thread1"){ @Override public void run() { map.put(3, 33); } }; new Thread("Thread2"){ @Override public void run() { map.put(4, 44); } }; new Thread("Thread3"){ @Override public void run() { map.put(7, 77); } }; System.out.println(map); } }
ConcurrentHashMap中默認是把segments初始化為長度為16的數組。
根據ConcurrentHashMap.segmentFor的算法,3、4對應的Segment都是segments[1],7對應的Segment是segments[12]。
(1)Thread1和Thread2先后進入Segment.put方法時,Thread1會首先獲取到鎖,可以進入,而Thread2則會阻塞在鎖上:
(2)切換到Thread3,也走到Segment.put方法,因為7所存儲的Segment和3、4不同,因此,不會阻塞在lock():
以上就是ConcurrentHashMap的工作機制,通過把整個Map分為N個Segment(類似HashTable),可以提供相同的線程安全,但是效率提升N倍,默認提升16倍。