zoukankan      html  css  js  c++  java
  • Java 并发--- 同步容器、ConcurrentModificationException异常

    同步容器

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

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

    上面这种情况不会抛出异常。

    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。
  • 相关阅读:
    MySQL开发规范与使用技巧总结
    Anaconda3(在D盘)安装jieba库具体步骤
    Python的reshape的用法
    oom和cpu负载的定位
    接口安全设计
    恍然间
    java原子类
    设计模式
    微服务
    常见的代码优化
  • 原文地址:https://www.cnblogs.com/hesier/p/5929604.html
Copyright © 2011-2022 走看看