1. <strong id="7actg"></strong>
    2. <table id="7actg"></table>

    3. <address id="7actg"></address>
      <address id="7actg"></address>
      1. <object id="7actg"><tt id="7actg"></tt></object>

        14個Java并發(fā)容器超強總結(jié)!

        共 3006字,需瀏覽 7分鐘

         ·

        2019-08-29 09:10

        來自:CSDN(作者:acupt)

        原文鏈接:

        https://blog.csdn.net/Design407/article/details/100084673?

        前言

        不考慮多線程并發(fā)的情況下,容器類一般使用ArrayList、HashMap等線程不安全的類,效率更高。在并發(fā)場景下,常會用到ConcurrentHashMap、ArrayBlockingQueue等線程安全的容器類,雖然犧牲了一些效率,但卻得到了安全。

        上面提到的線程安全容器都在java.util.concurrent包下,這個包下并發(fā)容器不少,今天全部翻出來鼓搗一下。

        僅做簡單介紹,后續(xù)再分別深入探索。

        并發(fā)容器介紹

        1. ConcurrentHashMap:并發(fā)版HashMap

        2. CopyOnWriteArrayList:并發(fā)版ArrayList

        3. CopyOnWriteArraySet:并發(fā)Set

        4. ConcurrentLinkedQueue:并發(fā)隊列(基于鏈表)

        5. ConcurrentLinkedDeque:并發(fā)隊列(基于雙向鏈表)

        6. ConcurrentSkipListMap:基于跳表的并發(fā)Map

        7. ConcurrentSkipListSet:基于跳表的并發(fā)Set

        8. ArrayBlockingQueue:阻塞隊列(基于數(shù)組)

        9. LinkedBlockingQueue:阻塞隊列(基于鏈表)

        10. LinkedBlockingDeque:阻塞隊列(基于雙向鏈表)

        11. PriorityBlockingQueue:線程安全的優(yōu)先隊列

        12. SynchronousQueue:讀寫成對的隊列

        13. LinkedTransferQueue:基于鏈表的數(shù)據(jù)交換隊列

        14. DelayQueue:延時隊列

        1.ConcurrentHashMap 并發(fā)版HashMap

        最常見的并發(fā)容器之一,可以用作并發(fā)場景下的緩存。底層依然是哈希表,但在JAVA 8中有了不小的改變,而JAVA 7和JAVA 8都是用的比較多的版本,因此經(jīng)常會將這兩個版本的實現(xiàn)方式做一些比較(比如面試中)。

        一個比較大的差異就是,JAVA 7中采用分段鎖來減少鎖的競爭,JAVA 8中放棄了分段鎖,采用CAS(一種樂觀鎖),同時為了防止哈希沖突嚴(yán)重時退化成鏈表(沖突時會在該位置生成一個鏈表,哈希值相同的對象就鏈在一起),會在鏈表長度達(dá)到閾值(8)后轉(zhuǎn)換成紅黑樹(比起鏈表,樹的查詢效率更穩(wěn)定)。

        2.CopyOnWriteArrayList 并發(fā)版ArrayList

        并發(fā)版ArrayList,底層結(jié)構(gòu)也是數(shù)組,和ArrayList不同之處在于:當(dāng)新增和刪除元素時會創(chuàng)建一個新的數(shù)組,在新的數(shù)組中增加或者排除指定對象,最后用新增數(shù)組替換原來的數(shù)組。

        適用場景:由于讀操作不加鎖,寫(增、刪、改)操作加鎖,因此適用于讀多寫少的場景。

        局限:由于讀的時候不會加鎖(讀的效率高,就和普通ArrayList一樣),讀取的當(dāng)前副本,因此可能讀取到臟數(shù)據(jù)。如果介意,建議不用。

        看看源碼感受下:

        20029678ac31d1ed39de533813e0ca69.webp

        3.CopyOnWriteArraySet 并發(fā)Set

        基于CopyOnWriteArrayList實現(xiàn)(內(nèi)含一個CopyOnWriteArrayList成員變量),也就是說底層是一個數(shù)組,意味著每次add都要遍歷整個集合才能知道是否存在,不存在時需要插入(加鎖)。

        適用場景:在CopyOnWriteArrayList適用場景下加一個,集合別太大(全部遍歷傷不起)。

        4.ConcurrentLinkedQueue 并發(fā)隊列(基于鏈表)

        基于鏈表實現(xiàn)的并發(fā)隊列,使用樂觀鎖(CAS)保證線程安全。因為數(shù)據(jù)結(jié)構(gòu)是鏈表,所以理論上是沒有隊列大小限制的,也就是說添加數(shù)據(jù)一定能成功。

        5.ConcurrentLinkedDeque 并發(fā)隊列(基于雙向鏈表)

        基于雙向鏈表實現(xiàn)的并發(fā)隊列,可以分別對頭尾進行操作,因此除了先進先出(FIFO),也可以先進后出(FILO),當(dāng)然先進后出的話應(yīng)該叫它棧了。

        6.ConcurrentSkipListMap 基于跳表的并發(fā)Map

        SkipList即跳表,跳表是一種空間換時間的數(shù)據(jù)結(jié)構(gòu),通過冗余數(shù)據(jù),將鏈表一層一層索引,達(dá)到類似二分查找的效果

        961ece336f81877ee90d71e328af2508.webp

        7.ConcurrentSkipListSet 基于跳表的并發(fā)Set

        類似HashSet和HashMap的關(guān)系,ConcurrentSkipListSet里面就是一個ConcurrentSkipListMap,就不細(xì)說了。

        8.ArrayBlockingQueue 阻塞隊列(基于數(shù)組)

        基于數(shù)組實現(xiàn)的可阻塞隊列,構(gòu)造時必須制定數(shù)組大小,往里面放東西時如果數(shù)組滿了便會阻塞直到有位置(也支持直接返回和超時等待),通過一個鎖ReentrantLock保證線程安全。

        用offer操作舉個例子:

        乍一看會有點疑惑,讀和寫都是同一個鎖,那要是空的時候正好一個讀線程來了不會一直阻塞嗎?

        答案就在notEmpty、notFull里,這兩個出自lock的小東西讓鎖有了類似synchronized + wait + notify的功能。

        9.LinkedBlockingQueue 阻塞隊列(基于鏈表)

        基于鏈表實現(xiàn)的阻塞隊列,想比與不阻塞的ConcurrentLinkedQueue,它多了一個容量限制,如果不設(shè)置默認(rèn)為int最大值。

        10.LinkedBlockingDeque 阻塞隊列(基于雙向鏈表)

        類似LinkedBlockingQueue,但提供了雙向鏈表特有的操作。

        11.PriorityBlockingQueue 線程安全的優(yōu)先隊列

        構(gòu)造時可以傳入一個比較器,可以看做放進去的元素會被排序,然后讀取的時候按順序消費。某些低優(yōu)先級的元素可能長期無法被消費,因為不斷有更高優(yōu)先級的元素進來。

        12.SynchronousQueue 數(shù)據(jù)同步交換的隊列

        一個虛假的隊列,因為它實際上沒有真正用于存儲元素的空間,每個插入操作都必須有對應(yīng)的取出操作,沒取出時無法繼續(xù)放入。

        一個簡單的例子感受一下:

        可以看到,寫入的線程沒有任何sleep,可以說是全力往隊列放東西,而讀取的線程又很不積極,讀一個又sleep一會。輸出的結(jié)果卻是讀寫操作成對出現(xiàn)。

        JAVA中一個使用場景就是Executors.newCachedThreadPool(),創(chuàng)建一個緩存線程池。

        13.LinkedTransferQueue 基于鏈表的數(shù)據(jù)交換隊列

        實現(xiàn)了接口TransferQueue,通過transfer方法放入元素時,如果發(fā)現(xiàn)有線程在阻塞在取元素,會直接把這個元素給等待線程。如果沒有人等著消費,那么會把這個元素放到隊列尾部,并且此方法阻塞直到有人讀取這個元素。和SynchronousQueue有點像,但比它更強大。

        14.DelayQueue 延時隊列

        可以使放入隊列的元素在指定的延時后才被消費者取出,元素需要實現(xiàn)Delayed接口。

        總結(jié)

        上面簡單介紹了JAVA并發(fā)包下的一些容器類,知道有這些東西,遇到合適的場景時就能想起有個現(xiàn)成的東西可以用了。想要知其所以然,后續(xù)還得再深入探索一番。


        推薦閱讀:


        3f8d4b6c057b95fd4f2471653b064dfd.webp喜歡我可以給我設(shè)為星標(biāo)哦3f8d4b6c057b95fd4f2471653b064dfd.webp

        0069b6b8d15ac22475f73def3d707d32.webp

        好文章,我?在看?

        7409bed2b633087ffabb7df7d04c95d0.webp
        瀏覽 88
        點贊
        評論
        收藏
        分享

        手機掃一掃分享

        分享
        舉報
        評論
        圖片
        表情
        推薦
        點贊
        評論
        收藏
        分享

        手機掃一掃分享

        分享
        舉報
        1. <strong id="7actg"></strong>
        2. <table id="7actg"></table>

        3. <address id="7actg"></address>
          <address id="7actg"></address>
          1. <object id="7actg"><tt id="7actg"></tt></object>
            亚洲中文字幕在线观看免费视频 | 亚洲永久无码7777kkk | 亚洲天堂黄片 | 伊人网免费视频 | 色欲一区 | 丰满岳跪趴高撅肥臀尤物小说 | 又大又粗出白浆少妇毛片 | 在线免费观看黄色小视频 | 动漫小舞被到高潮抖胸 | 瘦精品无码一区二区三区四区五区六区七区八区 |