java多線程(8)--ConcurrentHashMap使用

一.ConcurrentHashMap的簡要總結:

1、public V get(Object key)不涉及到鎖,也就是說獲得對象時沒有使用鎖;

2、put、remove方法要使用鎖,但並不一定有鎖爭用,原因在於ConcurrentHashMap將緩存的變量分到多個Segment,每個Segment上有一個鎖,只要多個線程訪問的不是一個Segment就沒有鎖爭用,就沒有堵塞,各線程用各自的鎖,ConcurrentHashMap缺省情況下生成16個Segment,也就是允許16個線程併發的更新而儘量沒有鎖爭用;

3、Iterator對象的使用,不一定是和其它更新線程同步,獲得的對象可能是更新前的對象,

ConcurrentHashMap允許一邊更新、一邊遍歷,也就是說在Iterator對象遍歷的時候,ConcurrentHashMap也可以進行remove,put操作,且遍歷的數據會隨着remove,put操作產出變化

所以希望遍歷到當前全部數據的話,要麼以ConcurrentHashMap變量爲鎖進行同步(synchronized該變量),要麼使用CopiedIterator包裝iterator,使其拷貝當前集合的全部數據,但是這樣生成的iterator不可以進行remove操作。

 

二.Hashtable和ConcurrentHashMap的不同點:

1、Hashtable對get,put,remove都使用了同步操作,它的同步級別是正對Hashtable來進行同步的,也就是說如果有線程正在遍歷集合,其他的線程就暫時不能使用該集合了,這樣無疑就很容易對性能和吞吐量造成影響,從而形成單點。而ConcurrentHashMap則不同,它只對put,remove操作使用了同步操作,get操作並不影響,詳情請看以上第1,2點,當前ConcurrentHashMap這樣的做法對一些線程要求很嚴格的程序來說,還是有所欠缺的,對應這樣的程序來說,如果不考慮性能和吞吐量問題的話,個人覺得使用Hashtable還是比較合適的;

2、Hashtable在使用iterator遍歷的時候,如果其他線程,包括本線程對Hashtable進行了put,remove等更新操作的話,就會拋出ConcurrentModificationException異常,但如果使用ConcurrentHashMap的話,就不用考慮這方面的問題了,詳情請看以上第3點;

 

1.HashMap或者ArrayList邊遍歷邊刪除數據會報Java.util.ConcurrentModificationException異常


  for (long i = 0; i < 15; i++) {  
            mReqPacket.put(i, i + "");  
        }  
  
        for (Entry<Long, String> entry : mReqPacket.entrySet()) {  
            long key = entry.getKey();  
            String value = entry.getValue();  
            if (key < 10) {  
                mReqPacket.remove(key);  
            }  
        }  
  
        for (Entry<Long, String> entry : mReqPacket.entrySet()) {  
            Log.d(entry.getKey() + " " + entry.getValue());  
        }  

所以要用迭代器刪除元素:

 for (long i = 0; i < 15; i++) {  
            mReqPacket.put(i, i + "");  
        }  
  
        for (Iterator<Entry<Long, String>> iterator = mReqPacket.entrySet().iterator(); iterator.hasNext();) {  
            Entry<Long, String> entry = iterator.next();  
            long key = entry.getKey();  
            if (key < 10) {  
                iterator.remove();  
            }  
        }  
  
        for (Entry<Long, String> entry : mReqPacket.entrySet()) {  
            Log.d(entry.getKey() + " " + entry.getValue());  
        }  

2.對ConcurrentHashMap邊遍歷邊刪除或者增加操作不會產生異常(可以不用迭代方式刪除元素),因爲其內部已經做了維護,遍歷的時候都能獲得最新的值。即便是多個線程一起刪除、添加元素也沒問題。

 for (long i = 0; i < 15; i++) {  
            conMap.put(i, i + "");  
        }  
  
        for (Entry<Long, String> entry : conMap.entrySet()) {  
            long key = entry.getKey();  
            if (key < 10) {  
                conMap.remove(key);  
            }  
        }  
  
        for (Entry<Long, String> entry : conMap.entrySet()) {  
            Log.d(entry.getKey() + " " + entry.getValue());  
        }  


3.一個線程對ConcurrentHashMap增加數據,另外一個線程在遍歷時就能獲得。

public static void main(String[] args) throws InterruptedException {  
    for (long i = 0; i < 5; i++) {  
        conMap.put(i, i + "");  
    }  
  
    Thread thread = new Thread(new Runnable() {  
        public void run() {  
            conMap.put(100l, "100");  
            Log.d("ADD:" + 100);  
            try {  
                Thread.sleep(100);  
            } catch (InterruptedException e) {  
                e.printStackTrace();  
            }  
        }  
  
    });  
    Thread thread2 = new Thread(new Runnable() {  
        public void run() {  
            for (Iterator<Entry<Long, String>> iterator = conMap.entrySet().iterator(); iterator.hasNext();) {  
                Entry<Long, String> entry = iterator.next();  
                Log.d(entry.getKey() + " - " + entry.getValue());  
                try {  
                    Thread.sleep(100);  
                } catch (InterruptedException e) {  
                    e.printStackTrace();  
                }  
            }  
        }  
    });  
    thread.start();  
    thread2.start();  
  
    Thread.sleep(3000);  
    Log.d("--------");  
    for (Entry<Long, String> entry : conMap.entrySet()) {  
        Log.d(entry.getKey() + " " + entry.getValue());  
    }  
  
}  

輸出:

    ADD:100  
    0 - 0  
    100 - 100  
    2 - 2  
    1 - 1  
    3 - 3  
    4 - 4  
    --------  
    0 0  
    100 100  
    2 2  
    1 1  
    3 3  
    4 4  


發佈了215 篇原創文章 · 獲贊 41 · 訪問量 34萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章