簡介:html
本文是主要介紹,併發容器CopyOnWriteArrayList和CopyOnWriteArraySet(不含重複元素的併發容器)的基本原理和使用示例。java
歡迎探討,若有錯誤敬請指正 編程
如需轉載,請註明出處 http://www.cnblogs.com/nullzx/數組
從類的名字咱們能夠看出,該類是基於ArrayList類實現的。而CopyOnWrite的意思顯然借鑑了操做系統中寫時拷貝的思想。該容器主要有如下特色:併發
1)讀取該容器中元素時,不加鎖。dom
2)寫操做,會加鎖,也就是說多個線程進行寫入操做時會逐個獲取鎖後進行寫入。ide
3)寫操做不會影響讀操做,也就是說線程要進行讀操做時,不會由於有線程正在進行寫操做而阻塞。ui
下面是寫操做源代碼this
public E set(int index, E element) { final ReentrantLock lock = this.lock; lock.lock(); try { Object[] elements = getArray(); E oldValue = get(elements, index); if (oldValue != element) { int len = elements.length; Object[] newElements = Arrays.copyOf(elements, len); newElements[index] = element; setArray(newElements); } else { // Not quite a no-op; ensures volatile write semantics setArray(elements); } return oldValue; } finally { lock.unlock(); } }
工做原理:在CopyOnWriteArrayList類中,定一了一個數組private transient volatile Object[] array;容器中存儲的對象的索引都會放在這個數組中。spa
寫操做首先會獲取鎖。當獲取鎖成功後,複製該數組到一個新的數組newElements中,而後修改或者添加某個元素(注意這個時候若是有線程來讀取該數組中的某個值,因爲讀操做不須要獲取鎖,因此不會被阻塞,可是可能不能讀取到最新修改後的值)。修改後,讓array指向通過修改後的新數組newElements,原array指向的數組會被垃圾回收器回收。
下面的代碼是CopyOnWriteArrayList的演示例程
package javalearning; import java.util.Random; import java.util.concurrent.CopyOnWriteArrayList; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; /*CopyOnWriteArrayList演示例程*/ public class CopyOnWriteArrayListDemo { /*定義一個CopyOnWriteArrayList對象,讀線程和寫線程會同時使用它*/ private CopyOnWriteArrayList<Integer> cowal = new CopyOnWriteArrayList<Integer>(); { /*對CopyOnWriteArrayList對象初始化*/ cowal.add(1); cowal.add(2); cowal.add(3); } private Random rnd = new Random(); public class ReadThread implements Runnable{ private String id; public ReadThread(String id){ this.id = id; } @Override public void run() { try { Thread.sleep(rnd.nextInt(1000)); } catch (InterruptedException e) { e.printStackTrace(); } /*讀線程會打印出CopyOnWriteArrayList對象的全部數值*/ System.out.println(id + " " + cowal.toString()); } } public class WriteThread implements Runnable{ /*寫線程會將CopyOnWriteArrayList對象的全部數值加1*/ @Override public void run() { for(int i = 0; i < cowal.size(); i++){ int x = cowal.get(i); /*每修改一個元素以前加鎖*/ cowal.set(i, x+1); /*修改完一個元素後釋放鎖*/ try{ Thread.sleep(rnd.nextInt(1000)); }catch(InterruptedException e){ e.printStackTrace(); } } } } public static void main(String[] args){ ExecutorService es = Executors.newCachedThreadPool(); CopyOnWriteArrayListDemo demo = new CopyOnWriteArrayListDemo(); /*建立兩個讀線程*/ es.execute(demo.new ReadThread("r1")); es.execute(demo.new ReadThread("r2")); /*建立兩個寫線程*/ es.execute(demo.new WriteThread()); es.execute(demo.new WriteThread()); es.shutdown(); while(!es.isTerminated()){ ; } System.out.println("====================="); /*CopyOnWriteArrayList對象中的最終值*/ System.out.println("eventual " + demo.cowal.toString()); } }
所有結束後,最終結果和咱們預想的一致。
r2 [2, 3, 3] r1 [2, 4, 3] ===================== eventual [2, 4, 5]
CopyOnWriteArraySet是一個不存貯重複對象的寫時拷貝容器。它的實現的原理很簡單,在其內部定義了一個CopyOnWriteArrayList對象al,當向該容器添加一個對象時,會調用addIfAbsent方法。
public boolean add(E e) { return al.addIfAbsent(e); }
3. 參考內容