Java多線程與並發庫高級應用-同步集合


ArrayBlockingQueue

LinkedBlockingQueue

數組是連續的一片內存

鏈表是不連續的一片內存

 傳統方式下用Collections工具類提供的synchronizedCollection方法來獲得同步集合。

java5中提供了如下一些同步集合類:

  > 通過看java.util.concurrent包下的介紹可以知道有哪些並發集合

  > ConcurrentHashMap 可以進行並發操作的HashMap,並發的HashMap還有 Collections.synchronizedMap(m) ,有了ConcurrentHashMap后,Collections.synchronizedMap(m)不怎么使用了。

  >ConcurrentSkipListMap 實現了SortedMap<K,V>  ,類似於TreeMap

  >ConcurrentSkipListSet 實現了SortedSet, 類似於TreeSet

  > CopyOnWriteArrayList

  > CopyOnWriteArraySet

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

使用Iterator對集合進行迭代時不能修改集合

 

public class CollectionModifyExceptionTest {

    public static void main(String[] args) {
        List<String> strs = new ArrayList<>();
        strs.add("aaa");
        strs.add("bbb");
        strs.add("ccc");
        Iterator iterator = strs.iterator();
        while(iterator.hasNext()){
            System.out.println(".....");
            String value = (String)iterator.next();
            if("aaa".equals(value)){
                strs.remove(value);
            }else{
                System.out.println(value);
            }
        }
    }

}

以上代碼在遍歷集合時,對集合進行修改,會拋出異常

Exception in thread "main" java.util.ConcurrentModificationException
at java.util.ArrayList$Itr.checkForComodification(ArrayList.java:859)
at java.util.ArrayList$Itr.next(ArrayList.java:831)
at com.java.thread.CollectionModifyExceptionTest.main(CollectionModifyExceptionTest.java:17)

異常拋在這一句 

String value = (String)iterator.next();
/**
     * An optimized version of AbstractList.Itr
     */
    private class Itr implements Iterator<E> {
        int cursor;       // index of next element to return
        int lastRet = -1; // index of last element returned; -1 if no such
        int expectedModCount = modCount;

        public boolean hasNext() { //
            return cursor != size;
        }

        @SuppressWarnings("unchecked")
        public E next() {
            checkForComodification(); int i = cursor;
            if (i >= size)
                throw new NoSuchElementException();
            Object[] elementData = ArrayList.this.elementData;
            if (i >= elementData.length)
                throw new ConcurrentModificationException();
            cursor = i + 1;
            return (E) elementData[lastRet = i];
        }

        public void remove() {
            if (lastRet < 0)
                throw new IllegalStateException();
            checkForComodification();

            try {
                ArrayList.this.remove(lastRet);
                cursor = lastRet;
                lastRet = -1;
                expectedModCount = modCount;
            } catch (IndexOutOfBoundsException ex) {
                throw new ConcurrentModificationException();
            }
        }

        final void checkForComodification() {
            if (modCount != expectedModCount)
                throw new ConcurrentModificationException();//此處拋異常 }
    }

 

 

然而在將"aaa" 改成"bbb"時,卻沒有拋出異常

因為在遍歷到 bbb 時,cursor為1(0,1,2),將 bbb 移除后size為2 進行下次遍歷是cursor為 2

所以hasNext()返回的為false 就不會進入循環。

 

要解決這個問題,可以使用 CopyOnWriteArrayList  在寫的時候有一份拷貝,

public static void main(String[] args) {
        List<String> strs = new CopyOnWriteArrayList();
        strs.add("aaa");
        strs.add("bbb");
        strs.add("ccc");
        Iterator iterator = strs.iterator();
        while(iterator.hasNext()){
            System.out.println(".....");
            String value = (String)iterator.next();
            if("aaa".equals(value)){
                strs.remove(value);
            }else{
                System.out.println(value);
            }
        }
    }

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM