并发的容器
并發(fā)的容器
文章目錄
- 并發(fā)的容器
- 1:JDK提供的并發(fā)容器
- 2:conlinkedlist
- 3:blockingqueue
- 3.1:你了解什么
- 3.2:arrayblockingqueue
- 3.3:linkedblockingqueue
- 3.4:priorityblockingqueue
- 4:concurrentskiplistmap
- 5:copyonwritearraylist
- 5.1實(shí)現(xiàn)原理
- 5.2 讀取操作
- 5.3寫操作
- 6:concurrenthashmap
1:JDK提供的并發(fā)容器
提供的都在java.util.concurrent包下面
- concurrnethashmap 線程安全的hashmap
- copyonwritearraylist 線程安全的list,在讀多于寫的情況下,非常實(shí)用
- concurrentlinkedlist:高效的并發(fā)隊(duì)列,使用鏈表連接,可以看作是線程安全的linkedlis,這是一個非阻塞隊(duì)列
- blockingqueue:接口,通過鏈表,數(shù)組等方式實(shí)現(xiàn)了這個接口。表示阻塞隊(duì)列,適用于數(shù)據(jù)共享的通道
- concurrnetskiplistmap:跳表的實(shí)現(xiàn),這是一個map,使用跳表的數(shù)據(jù)結(jié)構(gòu)進(jìn)行快速查詢
2:conlinkedlist
- Java提供的線程安全的queue可以分為阻塞隊(duì)列和非阻塞隊(duì)列,其中阻塞隊(duì)列的典型例子就是blockingqueue,非阻塞隊(duì)列就是concurrentlinkedqueue。阻塞隊(duì)列可以通過加鎖來實(shí)現(xiàn),非阻塞隊(duì)列可以使用CAS操作實(shí)現(xiàn)
- 從名字可以看出,concurrentlinkedqueue,這個使用鏈表來作為數(shù)據(jù)結(jié)構(gòu),主要使用cas非阻塞的算法來實(shí)現(xiàn)線程安全
- 適用于對隊(duì)列讀寫存在多個線程進(jìn)行的場所,如果對隊(duì)列加鎖的成本比較高那么就適合使用無所的concurrenlinkedqueue來實(shí)現(xiàn)
3:blockingqueue
3.1:你了解什么
- blockingqueue是線程安全的堵塞隊(duì)列,它使用加鎖的機(jī)制來實(shí)現(xiàn)
- 當(dāng)隊(duì)列的容器已經(jīng)滿了,生產(chǎn)者線程會被阻塞,直到隊(duì)列沒有滿
- 當(dāng)隊(duì)列容器為空的時候,消費(fèi)者線程會被阻塞,直到隊(duì)列到非空的時候
3.2:arrayblockingqueue
- 采用數(shù)組的方式來實(shí)現(xiàn),容量不能改變。
- 不管是插入還是讀取,都需要獲取到鎖才能夠操作
- 默認(rèn)情況下不能夠保證公平性,如果要保證,可以新建立的時候設(shè)置為true
3.3:linkedblockingqueue
- 基于單向鏈表實(shí)現(xiàn)的阻塞隊(duì)列,具有FIFO的性質(zhì)
- 一般需要在創(chuàng)建的時候指定大小,如果沒有指定,容量等于 MAX
3.4:priorityblockingqueue
- 支持優(yōu)先級的阻塞隊(duì)列,默認(rèn)情況下采用自然排序
- 并發(fā)控制采用reentrantLock,且在創(chuàng)建的時候必須指定容量的大小
- 不可以插入 null,同時必須是課比較大小的,否則會 classCastException
4:concurrentskiplistmap
- 給定一個單鏈表,即使鏈表是有序的,我們想要查詢一個數(shù)據(jù),也只能從頭遍歷到尾巴上,這樣的效率很低
- 跳表就不一樣,跳表是一種能偶來快速查找的數(shù)據(jù)結(jié)構(gòu),類似與平衡樹
- 對跳表的插入和刪除只需要對整個數(shù)據(jù)結(jié)構(gòu)的局部進(jìn)行操作,這樣帶來的好處就是,你只需要鎖住一部分就可以了
- 而在查詢的性能上,跳表的時間復(fù)雜度是 log n
- 跳表的本質(zhì)是維持了多個鏈表,并且每個鏈表之間是分層的
- 最底層的鏈表維護(hù)了跳表內(nèi)部的所有元素,每上面一層鏈表都是下面一層的子集
- 跳表內(nèi)的所有鏈表都是排序的,查找的時候,可以從頂部鏈表開始,一旦發(fā)現(xiàn)被查找的元素大于當(dāng)前鏈表中的取值,就會轉(zhuǎn)入下一層鏈表繼續(xù)找。
- 這也就是說在查找的過程中,搜索是跳躍式的,是一種以空間換取時間的數(shù)據(jù)結(jié)構(gòu)
- 使用跳表實(shí)現(xiàn)map和哈希算法不同之處是:哈希并不會保存元素的順序,但是跳表之中都是排序的,因此對跳表進(jìn)行遍歷的時候,你會得到一個有序的結(jié)果。
5:copyonwritearraylist
- 在很多的場景之下,讀操作可能會遠(yuǎn)遠(yuǎn)的大于寫操作,由于讀操作根本不會修改原有的數(shù)據(jù),所以對于每次的讀加鎖是一種資源的浪費(fèi),我們允許多個進(jìn)程同時讀取數(shù)據(jù)
- copyonwritearraylist,讀取是完全不用加鎖的,并且寫入也不會堵塞讀操作,只有寫入和寫入之間需要進(jìn)行同步的等待
5.1實(shí)現(xiàn)原理
- add,set都是創(chuàng)建底層數(shù)組的新的副本來實(shí)現(xiàn)的,當(dāng)list需要被修改的時候,并不修改當(dāng)前的數(shù)據(jù),而是對原有的數(shù)據(jù)進(jìn)行一次復(fù)制,將修改的內(nèi)容寫入副本。寫完之后,再將修改完的副本替換完原來的數(shù)據(jù),這樣就可以保證寫數(shù)據(jù)不會影響讀操作 。
5.2 讀取操作
- 讀取操作沒有任何的絨布機(jī)制和鎖操作,因?yàn)樽x取不會被數(shù)據(jù)造成任何的修改
5.3寫操作
- 寫入操作的時候,加了鎖,避免了多個線程同時修改,導(dǎo)致多個副本出來
6:concurrenthashmap
- hashmap不是線程安全的,
總結(jié)