十年網(wǎng)站開發(fā)經(jīng)驗 + 多家企業(yè)客戶 + 靠譜的建站團(tuán)隊
量身定制 + 運(yùn)營維護(hù)+專業(yè)推廣+無憂售后,網(wǎng)站問題一站解決
今天我們一起學(xué)習(xí)下java.util.concurrent并發(fā)包里的CopyOnWriteArrayList工具類。當(dāng)有多個線程可能同時遍歷、修改某個公共數(shù)組時候,如果不希望因使用synchronize關(guān)鍵字鎖住整個數(shù)組而影響性能,可以考慮使用CopyOnWriteArrayList。
10年積累的成都做網(wǎng)站、成都網(wǎng)站設(shè)計經(jīng)驗,可以快速應(yīng)對客戶對網(wǎng)站的新想法和需求。提供各種問題對應(yīng)的解決方案。讓選擇我們的客戶得到更好、更有力的網(wǎng)絡(luò)服務(wù)。我雖然不認(rèn)識你,你也不認(rèn)識我。但先網(wǎng)站制作后付款的網(wǎng)站建設(shè)流程,更有青山湖免費(fèi)網(wǎng)站建設(shè)讓你可以放心的選擇與我們合作。
CopyOnWriteArrayList的定義如下:
public class CopyOnWriteArrayList
extends Object
implements List, RandomAccess, Cloneable, Serializable
它也屬于Java集合框架的一部分,是[ArrayList]()的線程安全的變體,跟ArrayList的不同在于:CopyOnWriteArrayList針對數(shù)組的修改操作(add、set等)是基于內(nèi)部拷貝的一份數(shù)據(jù)而進(jìn)行的。換句話說,即使在一個線程進(jìn)行遍歷操作時有其他線程可能進(jìn)行插入或刪除操作,我們也可以“線程安全”得遍歷CopyOnWriteArrayList。
CopyOnWriteArrayList的實現(xiàn)原理是,在一個線程開始遍歷(創(chuàng)建Iterator對象)時,內(nèi)部會創(chuàng)建一個“快照”數(shù)組,遍歷基于這個快照Iterator進(jìn)行,在遍歷過程中這個快照數(shù)組不會改變,也就不會拋出ConcurrentModificationException
。如果在遍歷的過程中有其他線程嘗試改變數(shù)組的內(nèi)容,就會拷貝一份新的數(shù)據(jù)進(jìn)行變更,而后面再來訪問這個數(shù)組的線程,看到的就是變更過的數(shù)組。
創(chuàng)建一個CopyOnWriteArrayList數(shù)組numbers;
CopyOnWriteArrayList numbers = new CopyOnWriteArrayList<>(new Integer[]{1, 3, 5, 78});
?
創(chuàng)建一個遍歷器iterator;
Iterator iterator = numbers.iterator();
?
給numbers中增加(或刪除、修改)一個元素;
numbers.add(100);
?
利用iterator遍歷數(shù)組的元素,發(fā)現(xiàn)遍歷的結(jié)果是Iterator對象創(chuàng)建之前的;
List result = new LinkedList<>();
iterator.forEachRemaining(result::add);
assertThat(result).containsOnly(1, 3, 5, 78);
完整的例子如下:
package org.java.learn.concurrent.copyonwritearraylist;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.concurrent.CopyOnWriteArrayList;
import static org.assertj.core.api.Assertions.*;
/**
* 作用:
* User: duqi
* Date: 2017/11/9
* Time: 11:20
*/
public class CopyOnWriteArrayListExample {
public static void main(String[] args) {
CopyOnWriteArrayList numbers = new CopyOnWriteArrayList<>(new Integer[]{1, 3, 5, 78});
Iterator iterator = numbers.iterator();
numbers.add(100);
List result = new LinkedList<>();
iterator.forEachRemaining(result::add);
assertThat(result).containsOnly(1, 3, 5, 78);
Iterator iterator2 = numbers.iterator();
numbers.remove(3);
List result2 = new LinkedList<>();
iterator2.forEachRemaining(result2::add);
assertThat(result2).containsOnly(1, 3, 5, 78, 100);
}
}
由于CopyOnWriteArrayList的實現(xiàn)機(jī)制——>修改操作和讀操作拿到的Iterator對象指向的不是一個數(shù)組,因此不支持基于Iterator對象的方法結(jié)果的刪除:public void remove();
,例子代碼如下:
package org.java.learn.concurrent.copyonwritearraylist;
import java.util.Iterator;
import java.util.concurrent.CopyOnWriteArrayList;
/**
* 作用: User: duqi Date: 2017/11/9 Time: 13:40
*/
public class CopyOnWriteArrayListExample2 {
public static void main(String[] args) {
try {
testExceptionThrow();
} catch (Exception e) {
e.printStackTrace();
}
}
private static void testExceptionThrow() {
CopyOnWriteArrayList numbers = new CopyOnWriteArrayList<>(new Integer[]{1, 3, 5, 78});
Iterator integerIterator = numbers.iterator();
while (integerIterator.hasNext()) {
integerIterator.remove();
}
}
}
CopyOnWriteArrayList適合使用在讀操作遠(yuǎn)遠(yuǎn)大于寫操作的場景里,比如緩存。發(fā)生修改時候做copy,新老版本分離,保證讀的高性能,適用于以讀為主的情況。
本號專注于后端技術(shù)、JVM問題排查和優(yōu)化、Java面試題、個人成長和自我管理等主題,為讀者提供一線開發(fā)者的工作和成長經(jīng)驗,期待你能在這里有所收獲。