Java併發包中CopyOnWrite容器相關類簡介

簡介html

本文是主要介紹,併發容器CopyOnWriteArrayList和CopyOnWriteArraySet(不含重複元素的併發容器)的基本原理和使用示例。java

歡迎探討,若有錯誤敬請指正 編程

如需轉載,請註明出處 http://www.cnblogs.com/nullzx/數組


1. CopyOnWriteArrayList

從類的名字咱們能夠看出,該類是基於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]

2. CopyOnWriteArraySet

CopyOnWriteArraySet是一個不存貯重複對象的寫時拷貝容器。它的實現的原理很簡單,在其內部定義了一個CopyOnWriteArrayList對象al,當向該容器添加一個對象時,會調用addIfAbsent方法。

    public boolean add(E e) {
        return al.addIfAbsent(e);
    }

3. 參考內容

[1] 聊聊併發-Java中的Copy-On-Write容器 | 併發編程網 – ifeve.com

[2] Java併發編程:併發容器之CopyOnWriteArrayList(轉載)

相關文章
相關標籤/搜索