說(shuō)明:以下內(nèi)容皆屬于個(gè)人對(duì)源碼的理解罐呼,可能存在歧義、誤解猜丹、錯(cuò)誤及理解不全面的情況,還望指正
一啤贩、CopyOnWriteArrayList介紹
CopyOnWriteArrayList是ArrayList的線(xiàn)程安全變體待秃。底層通過(guò)創(chuàng)建數(shù)組的新副本來(lái)實(shí)現(xiàn)并發(fā)情況下對(duì)數(shù)組的更新操作(包括add、set等方法)痹屹。這種方式通常是花費(fèi)代價(jià)比較大的,但是當(dāng)遍歷操作遠(yuǎn)大于更新操作的情況時(shí)枉氮,這種方式卻是更有效的志衍。當(dāng)然,我們需要避免并發(fā)線(xiàn)程之間的干擾聊替。CopyOnWriteArrayList允許添加所有的元素楼肪,包括Null。
內(nèi)存一致性效果:與其他并發(fā)集合一樣惹悄,將對(duì)象放入CopyOnWriteArrayList之前的線(xiàn)程中的動(dòng)作發(fā)生在另一個(gè)線(xiàn)程的CopyOnWriteArrayList中訪(fǎng)問(wèn)或刪除該元素之后的操作之前春叫。
二、CopyOnWriteArrayList實(shí)現(xiàn)
- 構(gòu)造函數(shù)
CopyOnWriteArrayList提供了三個(gè)構(gòu)造函數(shù):默認(rèn)的構(gòu)造函數(shù)泣港,傳入指定集合的構(gòu)造函數(shù)暂殖,將指定數(shù)組拷貝到CopyOnWriteArrayList的構(gòu)造函數(shù)。目前只了解一下默認(rèn)構(gòu)造函數(shù)的實(shí)現(xiàn)当纱。
CopyOnWriteArrayList在調(diào)用構(gòu)造函數(shù)實(shí)例化對(duì)象的時(shí)候呛每,會(huì)創(chuàng)建一個(gè)大小為0的數(shù)組對(duì)象,將CopyOnWriteArrayList底層的數(shù)組對(duì)象變量指向這個(gè)數(shù)組坡氯。這個(gè)對(duì)象變量在源碼中的定義如下:
/** The array, accessed only via getArray/setArray. */
private transient volatile Object[] array;
底層數(shù)組變量array被聲明為volatile 類(lèi)型的晨横,這樣在對(duì)數(shù)組進(jìn)行遍歷的時(shí)候獲取的都是最新的值。那么并發(fā)訪(fǎng)問(wèn)數(shù)據(jù)遍歷的問(wèn)題就得以解決箫柳。
在創(chuàng)建CopyOnWriteArrayList對(duì)象實(shí)例時(shí)手形,同時(shí)會(huì)創(chuàng)建一個(gè)ReentranctLock的實(shí)例。
- add(E e)方法
調(diào)用CopyOnWriteArrayList的add()方法時(shí)悯恍,首先會(huì)用ReentranctLock實(shí)例的lock()方法獲取鎖库糠,然后獲取底層數(shù)組對(duì)象并將底層數(shù)組對(duì)象拷貝到一個(gè)新的數(shù)組對(duì)象中,將要添加的元素添加到新的數(shù)組對(duì)象中坪稽,最后調(diào)用setArray方法曼玩,將底層數(shù)組對(duì)象變量array引向新的數(shù)組對(duì)象。最后釋放鎖窒百。 - iterator()方法
iterator()方法其實(shí)是在內(nèi)部創(chuàng)建了一個(gè)COWIterator實(shí)例對(duì)象黍判,在該實(shí)例對(duì)象的內(nèi)部聲明一個(gè)數(shù)組的快照變量指向CopyOnWriteArrayList的底層數(shù)組。然后通過(guò)該變量進(jìn)行對(duì)數(shù)組元素的遍歷操作篙梢。與iterator()方法類(lèi)似的還有sublist()方法顷帖。 - 其它方法
CopyOnWriteArrayList的其它的更新操作基本與add()方法思想一直,都是先獲取鎖,在操作完成后將原有數(shù)組變量指向新的數(shù)組變量贬墩。最后在finally塊中釋放鎖榴嗅。
三、CopyOnWriteArrayList總結(jié)
從CopyOnWriteArrayList的實(shí)現(xiàn)陶舞,可以看出包含了2個(gè)思想:讀寫(xiě)分離和最終一致性(因?yàn)椴l(fā)訪(fǎng)問(wèn)情況下嗽测,某個(gè)線(xiàn)程作了元素的更新操作后,array變量尚未指向新數(shù)組前肿孵,其它線(xiàn)程訪(fǎng)問(wèn)的可能還是原來(lái)的數(shù)組里的元素)唠粥。對(duì)于多線(xiàn)程情況下,遍歷訪(fǎng)問(wèn)操作遠(yuǎn)大于更新操作的時(shí)候停做,CopyOnWriteArrayList無(wú)疑是最好的選擇晤愧,省略了我們自己去加同步的操作。但是數(shù)組的拷貝是一項(xiàng)費(fèi)時(shí)費(fèi)資源的操作蛉腌,對(duì)于非多線(xiàn)程或數(shù)據(jù)變化較多的情況下官份,還是避免使用。