java中為什麼Hashtable是執行緒安全的,而HashMap是執行緒不安全的?還有ArrayList為什麼是執行緒不安全的,Vector是執行緒安全的??
文章目錄
- 一、HashMap解析
- 二、Hashtable解析
- 三、Collections.synchronizedMap()解析
- 四、ConcurrentHashMap
- 六、ArrayList為什麼是執行緒不安全的,Vector是執行緒安全的?
- 參考文獻
什麼叫做執行緒安全?
在一個執行緒中,某操作執行之後得到的是該操作想要的結果,而不是其他結果(被其他執行緒修改了)
一、HashMap解析
HashMap是執行緒不安全的,多執行緒情況下不推薦使用HashMap。它的key,value執行為null
二、Hashtable解析
Hashtable在jdk1.1就有了,那麼它是怎樣實現執行緒安全的呢?主要看put、remove、get方法猜它肯定進行的同步控制的。於是看原始碼:
//get它搞成了同步方法,保證了get的安全性
public synchronized V get(Object key) {
……
}
//synchronized,同樣
public synchronized V put(K key, V value) {
……
}
//也是搞成了同步方法
public synchronized V remove(Object key) {
……
}
所以為什麼Hashtable是執行緒安全的,因為它的remove,put,get做成了同步方法,保證了Hashtable的執行緒安全性。
每個操作資料的方法都進行同步控制之後,由此帶來的問題任何一個時刻只能有一個執行緒可以操縱Hashtable,所以其效率比較低。
三、Collections.synchronizedMap()解析
我們看原始碼:
public int size() {
synchronized (mutex) {return m.size();}
}
public boolean isEmpty() {
synchronized (mutex) {return m.isEmpty();}
}
public boolean containsKey(Object key) {
synchronized (mutex) {return m.containsKey(key);}
}
public boolean containsValue(Object value) {
synchronized (mutex) {return m.containsValue(value);}
}
public V get(Object key) {
synchronized (mutex) {return m.get(key);}
}
public V put(K key, V value) {
synchronized (mutex) {return m.put(key, value);}
}
public V remove(Object key) {
synchronized (mutex) {return m.remove(key);}
}
public void putAll(Map<? extends K, ? extends V> map) {
synchronized (mutex) {m.putAll(map);}
}
public void clear() {
synchronized (mutex) {m.clear();}
}
我們驚人的發現,synchronizedMap只是將HashMap的操縱放在了同步程式碼塊中來保證SynchronizedMap的執行緒安全性。因此,SynchronizedMap也可以允許key和value為null。這樣帶來的問題也是任何一個時刻只能有一個執行緒可以操縱synchronizedMap,所以其效率比較低。
同樣,Collections下的SynchronizedXX也是用同樣方法實現執行緒安全性的。如SynchronizedSortedMap
四、ConcurrentHashMap
為什麼ConcurrentHashMap可以多執行緒訪問呢?是因為ConcurrentHashMap將Map分段了,每個段進行加鎖,而不是想Hashtable,SynchronizedMap是整個map加鎖,這樣就可以多執行緒訪問了。
如圖:
ConcurrentHashMap預設執行16個執行緒同時訪問該map。但是我們可以通過一個函式來設定增加或減少最大可執行訪問的執行緒數目。
//就是這個concurrencyLevel
public ConcurrentHashMap(int initialCapacity,
float loadFactor, int concurrencyLevel)
所以就有了下面這幾個問題:
(1) 多執行緒可以同時寫一個ConcurrentHashMap的分段嗎?
不行。分段就像一個單獨的HashMap,只允許一個執行緒向其寫入資料
(2)多個執行緒可以同時寫入不同分段嗎?
這當然可以咯!
(3)多個執行緒可以同時從一個分段中讀資料嗎?
可以
(4)如果一個執行緒正在向一個分段寫入資料,其他執行緒可以從該分段中讀取資料嗎?
可以。但是讀取到最後更新的資料。
最後需要注意的一點是CoucrrentHashMap是不允許key和vlaue為null的。
六、ArrayList為什麼是執行緒不安全的,Vector是執行緒安全的?
Vector肯定是做了同步控制了的。看原始碼
//同步方法
public synchronized void addElement(E obj) {
modCount++;
ensureCapacityHelper(elementCount + 1);
elementData[elementCount++] = obj;
}
//同步方法
public synchronized boolean removeElement(Object obj) {
modCount++;
int i = indexOf(obj);
if (i >= 0) {
removeElementAt(i);
return true;
}
return false;
}
所以Vector也是用同步方法的方式來保證執行緒安全的。
參考文獻
https://codepumpkin.com/hashtable-vs-synchronizedmap-vs-concurrenthashmap/