從JDK1.2起俱萍,就有了HashMap闲延,正如前一篇文章所說痊剖,HashMap不是線程安全的,因此多線程操作時需要格外小心垒玲。
在JDK1.5中陆馁,偉大的Doug Lea給我們帶來了concurrent包,從此Map也有安全的了合愈。
ConcurrentHashMap具體是怎么實現(xiàn)線程安全的呢叮贩,肯定不可能是每個方法加synchronized,那樣就變成了HashTable佛析。
從ConcurrentHashMap代碼中可以看出益老,它引入了一個“分段鎖”的概念,具體可以理解為把一個大的Map拆分成N個小的HashTable寸莫,根據(jù)key.hashCode()來決定把key放到哪個HashTable中捺萌。
在ConcurrentHashMap中,就是把Map分成了N個Segment储狭,put和get的時候互婿,都是現(xiàn)根據(jù)key.hashCode()算出放到哪個Segment中:
測試程序:
import java.util.concurrent.ConcurrentHashMap;
publicclass ConcurrentHashMapTest {
privatestatic ConcurrentHashMap map = new ConcurrentHashMap();
publicstaticvoid main(String[] args) {
new Thread("Thread1"){
@Override
publicvoid run() {
map.put(3, 33);
}
};
new Thread("Thread2"){
@Override
publicvoid run() {
map.put(4, 44);
}
};
new Thread("Thread3"){
@Override
publicvoid run() {
map.put(7, 77);
}
};
System.out.println(map);
}
}
ConcurrentHashMap中默認是把segments初始化為長度為16的數(shù)組。
根據(jù)ConcurrentHashMap.segmentFor的算法辽狈,3慈参、4對應的Segment都是segments[1],7對應的Segment是segments[12]刮萌。
- Thread1和Thread2先后進入Segment.put方法時驮配,Thread1會首先獲取到鎖,可以進入着茸,而Thread2則會阻塞在鎖上:
- 切換到Thread3壮锻,也走到Segment.put方法,因為7所存儲的Segment和3涮阔、4不同猜绣,因此睬关,不會阻塞在lock():
以上就是ConcurrentHashMap的工作機制小槐,通過把整個Map分為N個Segment(類似HashTable),可以提供相同的線程安全丙唧,但是效率提升N倍伟阔,默認提升16倍辣之。