CopyOnWriteArrayList

除了加鎖外,其實還有一種方式能夠防止併發修改異常,這就是將讀寫分離技術(不是數據庫上的)。 數據庫

先回顧一下一個常識: 數組

一、JAVA中「=」操做只是將引用和某個對象關聯,假如同時有一個線程將引用指向另一個對象,一個線程獲取這個引用指向的對象,那麼他們之間不會發生ConcurrentModificationException,他們是在虛擬機層面阻塞的,並且速度很是快,幾乎不須要CPU時間。 緩存

二、JAVA中兩個不一樣的引用指向同一個對象,當第一個引用指向另一個對象時,第二個引用還將保持原來的對象。 安全

 

基於上面這個常識,咱們再來探討下面這個問題: 多線程

在CopyOnWriteArrayList裏處理寫操做(包括add、remove、set等)是先將原始的數據經過JDK1.6的Arrays.copyof()來生成一份新的數組 併發

而後在新的數據對象上進行寫,寫完後再將原來的引用指向到當前這個數據對象(這裏應用了常識1),這樣保證了每次寫都是在新的對象上(由於要保證寫的一致性,這裏要對各類寫操做要加一把鎖,JDK1.6在這裏用了重入鎖), 性能

而後讀的時候就是在引用的當前對象上進行讀(包括get,iterator等),不存在加鎖和阻塞,針對iterator使用了一個叫COWIterator的閹割版迭代器,由於不支持寫操做,當獲取CopyOnWriteArrayList的迭代器時,是將迭代器裏的數據引用指向當前引用指向的數據對象,不管將來發生什麼寫操做,都不會再更改迭代器裏的數據對象引用,因此迭代器也很安全(這裏應用了常識2)。 線程

CopyOnWriteArrayList中寫操做須要大面積複製數組,因此性能確定不好,可是讀操做由於操做的對象和寫操做不是同一個對象,讀之間也不須要加鎖,讀和寫之間的同步處理只是在寫完後經過一個簡單的「=」將引用指向新的數組對象上來,這個幾乎不須要時間,這樣讀操做就很快很安全,適合在多線程裏使用,絕對不會發生ConcurrentModificationException,因此最後得出結論:CopyOnWriteArrayList適合使用在讀操做遠遠大於寫操做的場景裏,好比緩存。 對象

 

如何將ArrayList轉CopyOnWriteArrayList rem

ArrayList list = new ArrayList();
list.add("1");
list.add("2");

Object[] aa = list.toArray();


CopyOnWriteArrayList  cal = new CopyOnWriteArrayList(aa);

將ArrayList轉成數組,用數組去構造CopyOnWriteArrayList 對象

相關文章
相關標籤/搜索