JUC 7大並發容器原理詳解、及使用場景


抄自:https://mp.weixin.qq.com/s?src=11&timestamp=1584015610&ver=2212&signature=Q-zWO4KPgjp1IVjH0s1yEdJUDOpg6ZJi9vH3tGqC9UjGpH8p9yeXgzp-rdDGioCmkdsGfaq48l*CbjCzjF926rI1aW2wsrqvM2y02JVjHF5HvVvNllEf8h8TNR0I6vlv&new=1

並發編程系列

並發編程系列:Java線程池的使用方式,核心運行原理、以及注意事項

高並發編程系列:4種常用Java線程鎖的特點,性能比較、使用場景

 

01

並發容器的由來

 

在Java並發編程中,經常聽到Java集合類,同步容器、並發容器,那么他們有哪些具體分類,以及各自之間的區別和優劣呢?

 

只有把這些梳理清楚了,你才能真正掌握在高並發的環境下,正確使用好並發容器,我們先從Java集合類,同步容器談起。

 

 

1.什么是同步容器

 

Java的集合容器框架中,主要有四大類別:List、Set、Queue、Map,大家熟知的這些集合類ArrayList、LinkedList、HashMap這些容器都是非線程安全的。

 

如果有多個線程並發地訪問這些容器時,就會出現問題。

 

因此,在編寫程序時,在多線程環境下必須要求程序員手動地在任何訪問到這些容器的地方進行同步處理,這樣導致在使用這些容器的時候非常地不方便。

所以,Java先提供了同步容器供用戶使用。

 

同步容器可以簡單地理解為通過synchronized來實現同步的容器,比如Vector、Hashtable以及SynchronizedList等容器。

 

2.同步容器,主要的分類

  • Vector

  • Stack

  • HashTable

  • Collections.synchronized方法生成

 

 

02

同步容器面臨的問題

 

 

可以通過查看Vector,Hashtable等這些同步容器的實現代碼,可以看到這些容器實現線程安全的方式就是將它們的狀態封裝起來,並在需要同步的方法上加上關鍵字synchronized。

 

這樣做的代價是削弱了並發性,當多個線程共同競爭容器級的鎖時,吞吐量就會降低。

 

例如: HashTable只要有一條線程獲取了容器的鎖之后,其他所有的線程訪問同步函數都會被阻塞,因此同一時刻只能有一條線程訪問同步函數。

 

因此為了解決同步容器的性能問題,所以才有了並發容器。

 

 

03

什么是並發容器

 

java.util.concurrent包中提供了多種並發類容器。

 

並發類容器是專門針對多線程並發設計的,使用了鎖分段技術,只對操作的位置進行同步操作,但是其他沒有操作的位置其他線程仍然可以訪問,提高了程序的吞吐量。

 

采用了CAS算法和部分代碼使用synchronized鎖保證線程安全。

 

04

並發容器有哪些種類

 

 

1.ConcurrentHashMap

 

對應的非並發容器:HashMap

目標:代替Hashtable、synchronizedMap,支持復合操作

原理:JDK6中采用一種更加細粒度的加鎖機制Segment“分段鎖”,JDK8中采用CAS無鎖算法。

 

2.CopyOnWriteArrayList

 

對應的非並發容器:ArrayList

目標:代替Vector、synchronizedList

原理:利用高並發往往是讀多寫少的特性,對讀操作不加鎖,對寫操作,先復制一份新的集合,在新的集合上面修改,然后將新集合賦值給舊的引用,並通過volatile 保證其可見性,當然寫操作的鎖是必不可少的了。

 

3.CopyOnWriteArraySet

 

對應的非並發容器:HashSet

目標:代替synchronizedSet

原理:基於CopyOnWriteArrayList實現,其唯一的不同是在add時調用的是CopyOnWriteArrayList的addIfAbsent方法,其遍歷當前Object數組,如Object數組中已有了當前元素,則直接返回,如果沒有則放入Object數組的尾部,並返回。

 

4.ConcurrentSkipListMap

 

對應的非並發容器:TreeMap

目標:代替synchronizedSortedMap(TreeMap)

原理:Skip list(跳表)是一種可以代替平衡樹的數據結構,默認是按照Key值升序的。

 

5.ConcurrentSkipListSet

 

對應的非並發容器:TreeSet

目標:代替synchronizedSortedSet

原理:內部基於ConcurrentSkipListMap實現

 

6.ConcurrentLinkedQueue

 

不會阻塞的隊列

對應的非並發容器:Queue

原理:基於鏈表實現的FIFO隊列(LinkedList的並發版本)

 

7.LinkedBlockingQueue、ArrayBlockingQueue、PriorityBlockingQueue

 

對應的非並發容器:BlockingQueue

特點:拓展了Queue,增加了可阻塞的插入和獲取等操作

原理:通過ReentrantLock實現線程安全,通過Condition實現阻塞和喚醒

 

實現類:

  • LinkedBlockingQueue:基於鏈表實現的可阻塞的FIFO隊列

  • ArrayBlockingQueue:基於數組實現的可阻塞的FIFO隊列

  • PriorityBlockingQueue:按優先級排序的隊列

 

05

ConcurrentHashMap的實現

 

 

 

HashMap,Hashtable與ConcurrentHashMap都是實現的哈希表數據結構,在隨機讀取的時候效率很高。

 

Hashtable實現同步是利用synchronized關鍵字進行鎖定的,其是針對整張哈希表進行鎖定的,即每次鎖住整張表讓線程獨占,在線程安全的背后是巨大的浪費。

 

ConcurrentHashMap和Hashtable主要區別就是圍繞着鎖的粒度進行區別以及如何區鎖定。

 

上圖中,左邊是Hashtable的實現方式,可以看到鎖住整個哈希表;而右邊則是ConcurrentHashMap的實現方式,單獨鎖住每一個桶(segment).ConcurrentHashMap將哈希表分為16個桶(默認值),諸如get(),put(),remove()等常用操作只鎖當前需要用到的桶,而size()才鎖定整張表。

 

原來只能一個線程進入,現在卻能同時接受16個寫線程並發進入(寫線程需要鎖定,而讀線程幾乎不受限制)。

 

所以,才有了並發性的極大提升。

 

高並發編程,除了並發容器,還會涉及到並發工具類:CountDownLatch等,后續將詳細的介紹並發工具類,以及ConcurrentHashMap的底層實現細節,不僅要知其然,還要知其所以然,這樣才能更好的掌握好高並發編程。

 


免責聲明!

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



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