Java多线程与并发库高级应用-同步集合

时间:2022-01-02 17:29:39

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);
            }
        }
    }