1、分類
Atomic包厢漩,locks包蟋座,線程池&并發(fā)集合拗踢。
2、并發(fā)集合
(1)ConcurrentHashMap
? ? 建立在HashMap基礎(chǔ)上向臀,jdk1.7時(shí)是由多個(gè)Segement組成巢墅,每個(gè)Segment里面類似HashMap結(jié)構(gòu),默認(rèn)是有16個(gè)Segement券膀,此時(shí)最多可以允許16個(gè)線程并發(fā)操作君纫,Segement指定后不可擴(kuò)容;jdk1.8時(shí)拋棄了分段鎖三娩,結(jié)構(gòu)上和HashMap一直庵芭,鏈表加紅黑樹(shù)。
? ? jdk1.7的結(jié)構(gòu):
? ? 每一個(gè)Segment都是一個(gè)HashEntry<K,V>[] table雀监。
????public class ConcurrentHashMap?extends AbstractMap?implements ConcurrentMap,Serializable{
????????// 將整個(gè)hashmap分成幾個(gè)小的map双吆,每個(gè)segment都是一個(gè)鎖;與hashtable相比会前,這么設(shè)計(jì)的目的是對(duì)于put, remove等操作好乐,可以減少并發(fā)沖突,對(duì)不屬于同一個(gè)片段的節(jié)點(diǎn)可以并發(fā)操作瓦宜,大大提高了性能
????????final Segment[] segments;
????????// 本質(zhì)上Segment類就是一個(gè)小的hashmap蔚万,里面table數(shù)組存儲(chǔ)了各個(gè)節(jié)點(diǎn)的數(shù)據(jù),繼承了ReentrantLock, 可以作為互拆鎖使用
????????static final class Segment?extends ReentrantLock implements Serializable{?
?????????transient volatile HashEntry[] table;
?????????transient int count;
????????}
????????// 基本節(jié)點(diǎn)临庇,存儲(chǔ)Key反璃, Value值
????????static final class HashEntry{
????????????final int hash;
? ? ? ????? final K key;?
? ? ? ?????volatile V value;?
? ? ? ?????volatile HashEntry next;
????????}
????}
????jdk1.8的結(jié)構(gòu):
? ? 取消了segements字段昵慌,直接采用?transient volatile HashEntry[] table 保存數(shù)據(jù),采用table數(shù)組元素作為鎖淮蜈,從而實(shí)現(xiàn)了對(duì)每一行數(shù)據(jù)進(jìn)行加鎖斋攀,進(jìn)一步減少并發(fā)沖突的概率。
? ? 將table數(shù)組+單向鏈表的數(shù)據(jù)結(jié)構(gòu)梧田,變更為table數(shù)組+單向鏈表+紅黑樹(shù)的結(jié)構(gòu)淳蔼。單向鏈表的時(shí)間復(fù)雜度為O(n),紅黑樹(shù)的時(shí)間復(fù)雜度為O(logN)裁眯。
(2)CopyOnWriteArrayList
? ??CopyOnWriteArrayList是一個(gè)線程安全的ArrayList鹉梨,讀操作無(wú)鎖,add操作時(shí)采用拷貝一個(gè)新數(shù)組來(lái)操作穿稳,讀效率很高存皂,但是有可能有臟讀。
? ? 原理:
????在CopyOnWriteArrayList中司草,讀操作不同步艰垂,因?yàn)樗麄冊(cè)趦?nèi)部數(shù)據(jù)的快照上工作,所以多個(gè)迭代器可以同時(shí)遍歷而不會(huì)相互阻塞埋虹。
? ? 所有的寫操作都是同步的猜憎,他們?cè)趥浞輸?shù)組的副本上工作,寫操作完成后搔课,將原陣列替換為復(fù)制的陣列胰柑,并釋放鎖定。支持?jǐn)?shù)據(jù)變得易變爬泥,所以替換數(shù)組是原子操作柬讨。
? ? 寫操作后創(chuàng)建的迭代器將能夠看到修改的結(jié)構(gòu)。
? ? 寫時(shí)復(fù)制集合返回的迭代器不會(huì)拋出ConcurrentModificationException袍啡,因?yàn)樗麄冊(cè)跀?shù)組的快照上工作踩官,并且無(wú)論后續(xù)怎么修改,都會(huì)像迭代器創(chuàng)建時(shí)那樣完全返回元素境输,這里就可能出現(xiàn)臟讀現(xiàn)象蔗牡。
? ? 源碼解析:
? ? ? ?/** The lock protecting all mutators ,執(zhí)行寫時(shí)復(fù)制操作嗅剖,需要使用可重入鎖加鎖*/
????????final transient ReentrantLock lock =newReentrantLock();
? ? ? ?/** The array, accessed only via getArray/setArray.?對(duì)象數(shù)組辩越,用于存放元素 */
????????private transient volatile Object[] array;
? ? 添加操作:
????finalReentrantLock lock = this.lock;?
? ? lock.lock();
????try{?
?????????Object[] elements = getArray();
?????????int len = elements.length;
????????//拷貝原容器,長(zhǎng)度為原容器長(zhǎng)度加一
????????Object[] newElements = Arrays.copyOf(elements, len +1);
????????//在新副本上執(zhí)行添加操作
????????newElements[len] = e;
????????//將原容器引用指向新副本
????????setArray(newElements);
????????return true;?
?????}finally{
????????//解鎖
???????lock.unlock();
? ? }
(3)CopyOnWriteArraySet
? ? 基于CopyOnWriteArrayList實(shí)現(xiàn)信粮,但是添加時(shí)需要遍歷一下元素存在與否黔攒,所以效率會(huì)低一點(diǎn);hashSet也是在添加的時(shí)候遍歷,但是不是順序遍歷督惰,hashSet是基于hashMap實(shí)現(xiàn)的不傅,所以根據(jù)hashcode確定位置后,直接定位元素赏胚。
(4)BlockingQueue
? ? 實(shí)現(xiàn)類有ArrayBlockingQueue基于數(shù)組先進(jìn)先出蛤签,有界;LinkedBlockingQueue基于鏈表栅哀,默認(rèn)無(wú)界,可指定容量称龙;PriorityBlockingQueue 無(wú)界留拾。
3、lock
(1)AQS
? ? 提供基于Lock接口的并發(fā)基礎(chǔ)類鲫尊,主要使用CAS實(shí)現(xiàn)痴柔。目的是在并發(fā)狀態(tài)下管理被阻塞的線程。提供了一套通用的機(jī)制來(lái)管理同步狀態(tài)疫向,阻塞/喚醒線程咳蔚,管理等待隊(duì)列等。提供了acquire()搔驼、acquireShared()谈火、release()、releaseShared()舌涨、hasWaiters()糯耍、cas改狀態(tài)等方法。核心是等待隊(duì)列(CLH隊(duì)列)囊嘉。
(2)CLH隊(duì)列
? ? 雙向鏈表温技,節(jié)點(diǎn)是對(duì)線程的包裝,分獨(dú)占和共享兩種類型扭粱;用前一節(jié)點(diǎn)的某一屬性表示后一節(jié)點(diǎn)的狀態(tài)舵鳞;自旋方式不斷cas插入包含當(dāng)前線程的節(jié)點(diǎn)到尾部。
(3)Condition
? ? 一般配合lock使用琢蛤,await(),signal(),signalAll()蜓堕。
(4)ReentrantLock
? ? 基于AQS,里面有一個(gè)state值虐块,先CAS設(shè)置state俩滥,如果state!=0,但發(fā)現(xiàn)拿鎖的是自己則state++贺奠,獲取失敗的加到CLH隊(duì)列尾霜旧,內(nèi)部自選繼續(xù)獲取鎖。
4、Atomic
(1)AtomicInteger
? ? 里面由一個(gè)volatile修飾的value屬性挂据,為了保證值在線程間可見(jiàn)以清,并發(fā)操作采用CAS,可實(shí)現(xiàn)原子遞增崎逃。
? ? 源碼解析:
? ? ? ?其中var表示要被更新的對(duì)象掷倔,var2是原始值在內(nèi)存中的偏移地址,通過(guò)getIntVolatile方法拿到現(xiàn)在的值var5个绍,現(xiàn)在的var5是一個(gè)期望值勒葱。compareAndSwapInt是一個(gè)native方法,compareAndSwapInt(var1, var2, var5, var5 + var4)是根據(jù)var1和var2拿到內(nèi)存中的值巴柿,和期望值var5比較凛虽,如果與期望值相等,就將其更新為var5+var4广恢,該方法一直在嘗試凯旋,直到內(nèi)存中的值和期望值一樣時(shí),才能進(jìn)行修改钉迷,并返回修改前內(nèi)存的值至非。
? ? 同時(shí)還提供了一個(gè)compareAndSet方法,當(dāng)且僅當(dāng)期望值和內(nèi)存中的值相等時(shí)糠聪,才能執(zhí)行更新操作荒椭,可以保證多線程同時(shí)修改共享變量時(shí),只有一個(gè)線程可以修改成功舰蟆。
(2) AtomicStampedReference
? ? CAS可能發(fā)生ABA問(wèn)題戳杀,即一個(gè)變量原來(lái)是A,先被修改成B后夭苗,又修改回了A信卡,由于CAS操作知識(shí)比較當(dāng)前值和預(yù)期值是否一樣,在其他線程來(lái)看题造,該變量就好像沒(méi)有發(fā)生過(guò)改變傍菇。
? ? 這種問(wèn)題可以為數(shù)據(jù)添加一個(gè)時(shí)間戳,每次成功修改數(shù)據(jù)時(shí)界赔,不僅修改數(shù)據(jù)的值丢习,同時(shí)要更新時(shí)間戳的值,CAS操作時(shí)淮悼,不僅要比較當(dāng)前值和預(yù)期值咐低,還需要比較當(dāng)前時(shí)間戳和預(yù)期時(shí)間戳,兩者都滿足時(shí)才能修改成功袜腥。
? ? AtomicStampedReference就是這樣做的见擦,它不僅維護(hù)對(duì)象之,還維護(hù)一個(gè)時(shí)間戳,當(dāng)AtomicStampedReference對(duì)應(yīng)的值被修改時(shí)鲤屡,不僅要更新數(shù)據(jù)本身损痰,還要更新時(shí)間戳(版本號(hào))。
5酒来、線程池
Executor接口卢未,只有一個(gè)execute方法;Executors封裝了一些常用線程池的方法堰汉;ExecutorService接口辽社,繼承Executor,新增shutdown,submit翘鸭,invokeAll方法爹袁;ThreadPoolExcutor實(shí)現(xiàn)了ExecutorService,可用于創(chuàng)建線程池矮固;Future接口,含cancel譬淳,get档址,isDone方法。
常用線程池邻梆,可以通過(guò)Executor調(diào)用創(chuàng)建守伸,newFixedThreadPool,固定線程數(shù)量浦妄;newSingleThreadExecutor尼摹,單個(gè)線程;newCachedThreadPool剂娄,可調(diào)節(jié)線程數(shù)量線程池蠢涝,有核心數(shù)量和最大數(shù)量;newSingleThreadSceduledExecutor阅懦,可以執(zhí)行定時(shí)任務(wù)的線程池和二。
6、同步容器
同步容器主要包含Vector耳胎,Stack惯吕,HashTable,Collections類中提供靜態(tài)工廠方法創(chuàng)建的類(Collections.synchronizedXxxx等方法)怕午。
Vector實(shí)現(xiàn)了List接口废登,Vector實(shí)際上就是一個(gè)數(shù)組,和ArrayList類似郁惜,但是Vector中的方法都是synchronized方法堡距。
Stack也是一個(gè)同步容器,它的方法也用了synchronized進(jìn)行了同步,它實(shí)際上是繼承了Cector類吏颖。
HashTable實(shí)現(xiàn)了Map接口搔体,它和HashMap類似,但是HashTable進(jìn)行了同步處理半醉。
同步容器的缺陷:同步容器的原理就是在方法上使用synchronized修飾疚俱,那么這些方法每次只允許一個(gè)線程調(diào)用。所以其他視圖調(diào)用這個(gè)方法的線程只能等待缩多,那么性能就比非同步容器差呆奕。