JAVA線程16 - 新特性:同步集合

1、概述

傳統方式下的Collection在迭代集合時,不容許對集合進行修改。 java

傳統方式下用Collections工具類提供的synchronizedCollection方法來得到同步集合。分析該方法的實現源碼:其實就是把方法放到同步代碼塊中,鎖爲當前集合對象。 安全

Java5中提供了以下一些同步集合類: 
經過查看java.util.concurrent包下的介紹能夠知道有哪些併發集合,如:ConcurrentHashMap 、CopyOnWriteArrayList 、CopyOnWriteArraySet。

2、多線程中的集合問題

場景:有一個集合,對該集合採用迭代器進行遍歷以後,又對其添加了一個元素。 多線程

咱們分別使用Arralist、Vector、Collections.synchronizedList、Collections.synchronizedList使用synchronized關鍵字進行同步控制、使用java.util.concurrent包中的高效的同步集合ConcurrentLinkedQueue進行測試。 併發

首先建立一個任務,該任務遍歷集合,又對其添加了一個元素。
public class ModifyCollectionTask implements Runnable {
    Collection<Integer> list;
    Lock lock = null;

    public ModifyCollectionTask(Collection<Integer> slist, Lock lock) {
        this.list = slist;
        this.lock = lock;
    }

    public void run() {
        //lock.lock();
        //try{
        // 遍歷列表
        for (Integer num : list) {
            System.out.println("線程"+Thread.currentThread().getName()+"數據爲:"+num);
        }
        // 向列表添加元素
        list.add(30);
        //}finally{lock.unlock();}
    }
}

1. 使用ArraList集合

public class MultiThreadListTest {
    public static void main(String[] args) {
        Collection<Integer> list = new ArrayList<Integer>();
        list.add(6);
        list.add(3);
        list.add(43);
        list.add(88);
        list.add(1);

        Lock lock = new ReentrantLock();

        //啓動100個線程,在多線程環境下,測試集合的同步問題
        for (int i = 0; i < 100; i++) {
            new Thread(new ModifyCollectionTask(list, lock)).start();
        }
    }
}
結果:
拋出異常:java.util.ConcurrentModificationException

說明:
經常使用的集合類ArrayList、Map等在多線程操做同一對象時會發生不一樣步的線程而形成數據讀取和寫入錯誤;一般都是採用synchronized修飾符或Lock將那些方法括起來來確保它們在執行時不會被其餘線程打擾。
這樣作雖然解決了數據爭用問題,可是在併發性方面付出了更多的代價,由於在迭代期間鎖住整個List會阻塞其餘線程,使它們在很長一段時間內不能訪問這個列表。

2. 使用Vector集合

public class MultiThreadListTest {
    public static void main(String[] args) {
        Collection<Integer> list = new Vector<Integer>();
        list.add(6);
        list.add(3);
        list.add(43);
        list.add(88);
        list.add(1);

        Lock lock = new ReentrantLock();

        //啓動100個線程,在多線程環境下,測試集合的同步問題
        for (int i = 0; i < 100; i++) {
            new Thread(new ModifyCollectionTask(list, lock)).start();
        }
    }
}
結果:
拋出異常:java.util.ConcurrentModificationException

說明:
Vector雖然是線程同步的,但僅僅把ArrayList改爲Vector仍是不對。不管是ArrayList仍是Vector,只要是實現Collection接口的,都要遵循fail-fast(快速失敗)的檢測機制,即在迭代是時候,不能修改集合的元素。一旦發現違法這個規定就會拋出異常。
事實上,Vector相對於ArrayList的線程同步,體如今對集合元素是否髒讀上。即ArrayList容許髒讀,而Vector特殊的機制,不會出現髒讀,可是效率會不好。

3. 使用Collections工具類中的同步包裝方法,將線程不安全ArrayList進行包裝

public class MultiThreadListTest {
    public static void main(String[] args) {
        Collection<Integer> list = Collections.synchronizedList(new ArrayList<Integer>());
        list.add(6);
        list.add(3);
        list.add(43);
        list.add(88);
        list.add(1);

        Lock lock = new ReentrantLock();

        //啓動100個線程,在多線程環境下,測試集合的同步問題
        for (int i = 0; i < 100; i++) {
            new Thread(new ModifyCollectionTask(list, lock)).start();
        }
    }
}
結果:
拋出異常:java.util.ConcurrentModificationException

說明:
對於 Collections 的 synchronizedCollection 或者 synchronizedList 方法包裝過的集合來講,對於 iterator() 方法是須要用戶手工進行同步的。 

4. 使用java.util.concurrent包中的ConcurrentLinkedQueue高效的同步集合

將ModifyCollectionTask類中的鎖相關代碼註釋加上,恢復到最初。
public class MultiThreadListTest {
    public static void main(String[] args) {
        Collection<Integer> list = new ConcurrentLinkedQueue<Integer>();
        list.add(6);
        list.add(3);
        list.add(43);
        list.add(88);
        list.add(1);

        Lock lock = new ReentrantLock();

        //啓動100個線程,在多線程環境下,測試集合的同步問題
        for (int i = 0; i < 100; i++) {
            new Thread(new ModifyCollectionTask(list, lock)).start();
        }
    }
}
結果:
沒出現異常。

說明:
對於 java.util.concurrent 中的任何集合都是通過精心設計的,不管迭代、增長、刪除都是線程而全的,並且在迭代時不會拋了 ConcurrentModificationException 的異常。



3、參考資料

http://blog.csdn.net/itm_hadf/article/details/7506529 http://long-yu2.iteye.com/blog/1530278 http://blog.csdn.net/johnny901114/article/details/8696032
相關文章
相關標籤/搜索