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異常

    Map<Long, String> mReqPacket = new HashMap<Long, String>();
            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());
            }

 




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

  

Map<Long, String> mReqPacket = new HashMap<Long, String>();
            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邊遍歷邊刪除或者增加操作不會產生異常(可以不用迭代方式刪除元素),因為其內部已經做了維護,遍歷的時候都能獲得最新的值。即便是多個線程一起刪除、添加元素也沒問題。

   Map<Long, String> conMap = new ConcurrentHashMap<Long, String>();
            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增加數據,另外一個線程在遍歷時就能獲得。

     

      static Map<Long, String> conMap = new ConcurrentHashMap<Long, String>();
        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
---------------------
版權聲明:本文為CSDN博主「Loongxu」的原創文章,遵循CC 4.0 by-sa版權協議,轉載請附上原文出處鏈接及本聲明。
原文鏈接:https://blog.csdn.net/heng615975867/article/details/52799213


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM