Java 併發--- 同步容器、ConcurrentModificationException異常

同步容器

在Java中,同步容器主要包括2類:java

  1. Vector、Stack、HashTable。Vector實現了List接口,Vector實際上就是一個數組,和ArrayList相似,可是Vector中的方法都是synchronized方法,即進行了同步措施。Stack也是一個同步容器,它的方法也用synchronized進行了同步,它其實是繼承於Vector類。HashTable實現了Map接口,它和HashMap很類似,可是HashTable進行了同步處理,而HashMap沒有。
  2. Collections類中提供的靜態工廠方法建立的類。
Collections.synchronizedCollection(Collection<T> c)
Collections.synchronizedSet(Set<T> s)
Collections.synchronizedList(List<T> list)
Collections.synchronizedMap(Map<K,V> m)

同步容器的缺陷:數組

  1. 從同步容器的具體實現源碼可知,同步容器中的方法採用了synchronized進行了同步,這必然會影響到執行性能。
  2. 同步容器並不能保證全部操做都是現成安全的。
  3. 在對Vector等容器併發地進行迭代修改時,會報ConcurrentModificationException異常。

ConcurrentModificationException異常

對Vector、ArrayList在迭代的時候若是同時對其進行修改就會拋出java.util.ConcurrentModificationException異常。即:安全

public class Test {
    public static void main(String[] args)  {
        ArrayList<Integer> list = new ArrayList<Integer>(Arrays.asList(1,2));
        Iterator<Integer> iterator = list.iterator();
        while(iterator.hasNext()){
            Integer integer = iterator.next();
            if(integer == 2)
                list.remove(integer);
        }
    }
}

結果拋出異常:java.util.ConcurrentModificationException多線程

一樣併發

for(Integer i: list){
        if(2 == i){
            list.remove(i);
        }
    }

也會拋出異常。性能

可是有一點,java7下,要修改的元素不是list的最後一位則不會拋異常,不懂。線程

ArrayList<Integer> list = new ArrayList<Integer>(Arrays.asList(1,2,3));
    Iterator<Integer> iterator = list.iterator();
    while(iterator.hasNext()){
        Integer integer = iterator.next();
        if(integer == 2)
            list.remove(integer);
    }

上面這種狀況不會拋出異常。code

ConcurrentModificationException 異常緣由

// TODO 分析源碼繼承

緣由:調用list.remove()方法致使modCount和expectedModCount的值不一致。接口

單線程下解決辦法

(1)調用Iterator.remove()

public class Test {
    public static void main(String[] args)  {
        ArrayList<Integer> list = new ArrayList<Integer>(Arrays.asList(1,2));
        Iterator<Integer> iterator = list.iterator();
        while(iterator.hasNext()){
            Integer integer = iterator.next();
            if(integer == 2)
                iterator.remove();   //注意這個地方
        }
    }
}

(2)額外使用list保存要刪除的元素

ArrayList<Integer> list = new ArrayList<>(Arrays.asList(1,2));
    Iterator<Integer> iterator = list.iterator();
    
    ArrayList<Integer> toRemove = new ArrayList<>();

    while (iterator.hasNext()){
        Integer integer = iterator.next();
        if(integer == 2){
            toRemove.add(integer);
        }
    }

    list.removeAll(toRemove);

多線程下解決辦法

上述方法中的第一種,在多線程下並不適用。無論使用的是ArrayList仍是線程安全的Vector,均可能會拋出異常。

一般的兩種解決辦法:

  1. 在使用iterator迭代的時候使用synchronized或者Lock進行同步;
  2. 使用併發容器CopyOnWriteArrayList代替ArrayList和Vector。
相關文章
相關標籤/搜索