java集合之CopyOnWriteArrayList

CopyOnWriteArrayList

CopyOnWriteArrayList是juc中提供的并發(fā)安全的ArrayList,我們拆分一下類名"Copy""On""Write""ArrayList"秆吵,從字面意思我們推斷出调煎,這個(gè)是以在Write時(shí)進(jìn)行Copy數(shù)組元素的ArrayList;

它主要具有一下特性:

  • 它是線程安全的铺遂;
  • 允許元素為null衫哥;
  • 支持隨機(jī)訪問、淺拷貝襟锐,可序列化撤逢;
  • 迭代器使用快照方式,且在迭代期間數(shù)組不會(huì)改變,故不會(huì)出現(xiàn)并發(fā)異常蚊荣;
  • 可變操作(set初狰,add,remove妇押,clear跷究,replace,sort敲霍,sublist等等)的開銷很大俊马,因?yàn)橥ǔP枰獜?fù)制整個(gè)基礎(chǔ)數(shù)組;
  • 所有的get方法只是獲取數(shù)組對(duì)應(yīng)下標(biāo)上的元素(無需加鎖控制)

CopyOnWriteArrayList使用了一種叫寫時(shí)復(fù)制的方法肩杈,當(dāng)有新元素添加到CopyOnWriteArrayList時(shí)柴我,先將原有數(shù)組的元素拷貝到新數(shù)組中,然后在新的數(shù)組中做寫操作扩然,寫完之后艘儒,再將原來的數(shù)組引用(volatile修飾的數(shù)組引用)指向新數(shù)組;

CopyOnWriteArrayList提供了弱一致性的迭代器夫偶,保證在獲取迭代器后界睁,其他線程對(duì)list的修改該不可見,迭代器遍歷時(shí)候的數(shù)組是獲取迭代器時(shí)候的一個(gè)快照兵拢;

CopyOnWriteArrayList是使用空間換時(shí)間的方式進(jìn)行工作翻斟,它主要適用于讀多些少,并且數(shù)據(jù)內(nèi)容變化比較少的場景(最好初始化時(shí)就進(jìn)行加載數(shù)據(jù)到CopyOnWriteArrayList中)说铃;

  • add(E e):添加元素
public boolean add(E e) {
/**
* 增加元素 e 到數(shù)組的末尾
* 操作步驟:
* 1. 獲取全局的 reentrantLock
* 2. 將原來的 array1 copy 到一個(gè) array.length + 1 的數(shù)組 array2 里面
* 3. 將 先添加的元素e添加到新數(shù)組 array2 的最后一個(gè)空間里面 (array2[array2.length - 1] = e)
* 4. 將 新數(shù)組 array2 賦值給 CopyOnWriteArrayList 中的 array
*/
final ReentrantLock lock = this.lock;
lock.lock(); // 1. 獲取 全局 lock
try{
Object[] elements = getArray(); // 2. 獲取原來的數(shù)組
int len = elements.length;
Object[] newElements = Arrays.copyOf(elements, len + 1); // 3. 新建一個(gè) array2 將原來的數(shù)據(jù)賦值到這個(gè)新建的數(shù)組里面
newElements[len] = e; // 4. 將 e 賦值給 array2的最后一個(gè)空間里面
setArray(newElements); // 5. 將新數(shù)組 array2 賦值給 CopyOnWriteArrayList 中的 array
return true;
}finally {
lock.unlock(); // 6. 釋放鎖
}

}
  • add(int index, E element):添加元素到指定位置
public void add(int index, E element) {
/**
* 將元素 e 插入到數(shù)組 指定的索引下標(biāo) index 下
* 操作步驟:
* 1. 獲取全局的鎖
* 2. 獲取 CopyOnWriteArrayList 的 array, 及 array.length
* 3. 進(jìn)行參數(shù)校驗(yàn) (index > len || index < 0) 則直接拋異常 -> 說明元素的插入只能在 0 - array.length 之間(包含兩個(gè)端點(diǎn))
* 4. 獲取插入點(diǎn) index 與 array.length 之間的步長, 進(jìn)行分類討論
* 1) 插入的數(shù)據(jù)正好在 原array數(shù)組的后一個(gè)節(jié)點(diǎn) (numMoved = len), 則直接新建一個(gè) array, 將原來的 array copy 過來
* 2) 插入的 index 滿足 0 <= index <= len - 1, 則新建一個(gè)數(shù)組, 原來 o -> index(index不包含) 拷貝來, index后面的數(shù)據(jù)拷貝到新數(shù)組的 index + 1 的空間
* 5. 將 e 設(shè)置到 新 array 的 index 位置
* 6. 將 新 array 設(shè)置到 CopyOnWriteArrayList 里面
*/
final ReentrantLock lock = this.lock;
lock.lock(); // 1. 獲取全局的鎖
try{
Object[] elements = getArray();
int len = elements.length;
if(index > len || index < 0){
throw new IndexOutOfBoundsException("Index: " + index + ", Size:" + len);
}
Object[] newElements;
int numMoved = len - index;
if(numMoved == 0){ // 走到這一步, 說明數(shù)據(jù)是插入到oldArray.length(這個(gè)值是指下標(biāo)) 位置上的元素
newElements = Arrays.copyOf(elements, len + 1); // 直接拷貝原數(shù)組到一個(gè)新的 array 數(shù)組中, 這個(gè)數(shù)組的長度是 len + 1
}else{
newElements = new Object[len + 1];
System.arraycopy(elements, 0, newElements, 0, index); // 將原數(shù)組 index 前的數(shù)組都拷貝到新的數(shù)組里面
System.arraycopy(elements, index, newElements, index + 1, numMoved); // 將原數(shù)組 index 以后的元素都 copy到新的數(shù)組里面(包括index位置的元素)
}
newElements[index] = element; // 將 index 賦值 element
setArray(newElements); // 將 新的 array set到 CopyOnWriteArrayList 上
}finally {
lock.unlock();
}
}
  • remove(int index):刪除指定位置元素
public E remove(int index) {
final ReentrantLock lock = this.lock;
lock.lock();
try{
Object[] elements = getArray();
int len = elements.length;
E oldValue = get(elements, index);
int numMoved = len - index - 1;
if(numMoved == 0){ // 說明刪除的元素的位置在 len - 1 上, 直接拷貝原數(shù)組的前 len - 1 個(gè)元素
setArray(Arrays.copyOf(elements, len - 1));
}else{
Object[] newElements = new Object[len - 1];
System.arraycopy(elements, 0, newElements, 0, index); // 拷貝原數(shù)組 0 - index之間的元素 (index 不拷貝)
System.arraycopy(elements, index + 1, newElements, index, numMoved); // 拷貝原數(shù)組 index+1 到末尾之間的元素 (index+1也進(jìn)行拷貝)
setArray(newElements);
}
}finally {
lock.unlock();
}
return null;
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末访惜,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子腻扇,更是在濱河造成了極大的恐慌债热,老刑警劉巖,帶你破解...
    沈念sama閱讀 217,509評(píng)論 6 504
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件幼苛,死亡現(xiàn)場離奇詭異窒篱,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)舶沿,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,806評(píng)論 3 394
  • 文/潘曉璐 我一進(jìn)店門舌剂,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人暑椰,你說我怎么就攤上這事〖鼍” “怎么了一汽?”我有些...
    開封第一講書人閱讀 163,875評(píng)論 0 354
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經(jīng)常有香客問我召夹,道長岩喷,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,441評(píng)論 1 293
  • 正文 為了忘掉前任监憎,我火速辦了婚禮纱意,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘鲸阔。我一直安慰自己偷霉,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,488評(píng)論 6 392
  • 文/花漫 我一把揭開白布褐筛。 她就那樣靜靜地躺著类少,像睡著了一般。 火紅的嫁衣襯著肌膚如雪渔扎。 梳的紋絲不亂的頭發(fā)上硫狞,一...
    開封第一講書人閱讀 51,365評(píng)論 1 302
  • 那天,我揣著相機(jī)與錄音晃痴,去河邊找鬼残吩。 笑死,一個(gè)胖子當(dāng)著我的面吹牛倘核,可吹牛的內(nèi)容都是我干的泣侮。 我是一名探鬼主播,決...
    沈念sama閱讀 40,190評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼笤虫,長吁一口氣:“原來是場噩夢啊……” “哼旁瘫!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起琼蚯,我...
    開封第一講書人閱讀 39,062評(píng)論 0 276
  • 序言:老撾萬榮一對(duì)情侶失蹤酬凳,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后遭庶,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體宁仔,經(jīng)...
    沈念sama閱讀 45,500評(píng)論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,706評(píng)論 3 335
  • 正文 我和宋清朗相戀三年峦睡,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了翎苫。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 39,834評(píng)論 1 347
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡榨了,死狀恐怖煎谍,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情龙屉,我是刑警寧澤呐粘,帶...
    沈念sama閱讀 35,559評(píng)論 5 345
  • 正文 年R本政府宣布满俗,位于F島的核電站,受9級(jí)特大地震影響作岖,放射性物質(zhì)發(fā)生泄漏唆垃。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,167評(píng)論 3 328
  • 文/蒙蒙 一痘儡、第九天 我趴在偏房一處隱蔽的房頂上張望辕万。 院中可真熱鬧,春花似錦沉删、人聲如沸渐尿。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,779評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽涡戳。三九已至,卻和暖如春脯倚,著一層夾襖步出監(jiān)牢的瞬間渔彰,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,912評(píng)論 1 269
  • 我被黑心中介騙來泰國打工推正, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留恍涂,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 47,958評(píng)論 2 370
  • 正文 我出身青樓植榕,卻偏偏與公主長得像再沧,于是被迫代替她去往敵國和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子尊残,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,779評(píng)論 2 354

推薦閱讀更多精彩內(nèi)容

  • 一炒瘸、基礎(chǔ)知識(shí):1、JVM寝衫、JRE和JDK的區(qū)別:JVM(Java Virtual Machine):java虛擬機(jī)...
    殺小賊閱讀 2,378評(píng)論 0 4
  • 在經(jīng)過一次沒有準(zhǔn)備的面試后顷扩,發(fā)現(xiàn)自己雖然寫了兩年的android代碼,基礎(chǔ)知識(shí)卻忘的差不多了慰毅。這是程序員的大忌隘截,沒...
    猿來如癡閱讀 2,839評(píng)論 3 10
  • Java集合框架 Java中封裝了許多常用的數(shù)據(jù)結(jié)構(gòu),稱為集合框架汹胃,可以有效組織數(shù)據(jù)婶芭,提高程序性能。最初Java只...
    Steven1997閱讀 933評(píng)論 0 2
  • 今天是12月12日着饥。雙十二購物狂歡節(jié)犀农。作為一個(gè)平時(shí)不怎么喜歡網(wǎng)購的我來說,這個(gè)節(jié)日對(duì)我來說沒有感覺宰掉。隨著時(shí)間的推進(jìn)...
    小坤爸閱讀 140評(píng)論 0 0
  • 忘記掉這句話是從哪里看到了,但是我想把這句話送給自己仇穗,即將迎來20歲生日的自己。 很多時(shí)候戚绕,我缺乏勇氣纹坐。我常常被自...
    zhishijuncc閱讀 294評(píng)論 0 1