您当前的位置: 首页 >  安全

星夜孤帆

暂无认证

  • 5浏览

    0关注

    626博文

    0收益

  • 0浏览

    0点赞

    0打赏

    0留言

私信
关注
热门博文

集合类不安全问题解析

星夜孤帆 发布时间:2020-12-07 11:37:44 ,浏览量:5

一、并发修改异常 1.1 ArrayList代码示例
public class ContainerNotSafeDemo {
    public static void main(String[] args) {
        List list = new ArrayList();
        for (int i=1; i  {
                list.add(UUID.randomUUID().toString().substring(0, 8));
                System.out.println(list);
            }, String.valueOf(i)).start();
        }
        //java.util.concurrentModificationException
    }
}
 1.2 ConcurrentModificationException

多次运行,可能会出现ConcurrentModificationException并发修改异常

ArrayList的add方法并没有加锁,单线程情况下不会有什么问题,但是,多线程并发情况下,可能出现并发问题。

通俗解释

上课签到表,正常加锁情况下,老师(锁)在前面盯着,来一个人签到一个人,等前一个人写完名字后,后一个人才能写。假如,现在没有老师(锁),当小明正在写名字时,刚写了一半,嗖一下,被小刚抢走了,这就是并发修改异常。

1.3 解决方案之Vector
public class ContainerNotSafeDemo {
    public static void main(String[] args) {
        List list = new Vector(); //new ArrayList();
        for (int i=1; i  {
                list.add(UUID.randomUUID().toString().substring(0, 8));
                System.out.println(list);
            }, String.valueOf(i)).start();
        }
        //java.util.concurrentModificationException
        /**
         * 1 故障现象
         *      java.util.ConcurrentModificationException
         * 2 导致原因
         *
         * 3 解决方案
         *      3.1 new Vector();
         *      3.2 Collections.synchronizedList(new ArrayList());
         *
         * 4 优化建议(同样的错误不犯第2次)
         */
    }
}

Vector可以解决上面的问题,因为Vector的add方法加了synchronized锁,一致性得到了解决,但是效率急剧降低,所以,很少使用

1.4 解决方案之Collections.synchronizedList
public class ContainerNotSafeDemo {
    public static void main(String[] args) {
        List list = Collections.synchronizedList(new ArrayList());
        for (int i=1; i  {
                list.add(UUID.randomUUID().toString().substring(0, 8));
                System.out.println(list);
            }, String.valueOf(i)).start();
        }
        //java.util.concurrentModificationException
        /**
         * 1 故障现象
         *      java.util.ConcurrentModificationException
         * 2 导致原因
         *
         * 3 解决方案
         *      3.1 new Vector();
         *      3.2 Collections.synchronizedList(new ArrayList());
         *
         * 4 优化建议(同样的错误不犯第2次)
         */
    }
}

此时,也可以解决,此外,还有其他的Collections类

二、写时复制 2.1  解决方案之写时复制(copyOnWrite)
public class ContainerNotSafeDemo {
    public static void main(String[] args) {
        List list = new CopyOnWriteArrayList();
        for (int i=1; i  {
                list.add(UUID.randomUUID().toString().substring(0, 8));
                System.out.println(list);
            }, String.valueOf(i)).start();
        }
        //java.util.concurrentModificationException
        /**
         * 1 故障现象
         *      java.util.ConcurrentModificationException
         * 2 导致原因
         *      并发争抢修改导致,参考我们的花名册签名情况
         *      一个人正在写入,另外一个同学过来抢夺,导致数据不一致异常。并发修改异常
         * 3 解决方案
         *      3.1 new Vector();
         *      3.2 Collections.synchronizedList(new ArrayList());
         *      3.3 new CopyOnWriteArrayList();
         *
         * 4 优化建议(同样的错误不犯第2次)
         */
    }
}

总之,没写完的时候,还没有返回true,我们用旧的;写完了返回了true,我们用新的

写时复制

CopyOnWrite容器,即写时复制的容器。往一个容器添加元素的时候,不直接往当前容器Object[]添加,而是先将当前容器Object[]进行Copy,复制出一个新的容器Object[] newElements,然后往新的容器Object[] newElements里添加元素,添加完元素之后,再将原容器的引用指向新的容器setArray(newElements);这样做的好处是可以对CopyOnWrite容器进行并发的读,而不需要加锁,因为当前容器不会添加任何元素。所以CopyOnWrite容器也是一种读写分离的思想,读和写不同的容器。

三、集合不安全类之Set
    private static void setNotSafe() {
        Set set = new CopyOnWriteArraySet();
        for (int i = 1; i  {
                set.add(UUID.randomUUID().toString().substring(0, 8));
                System.out.println(set);
            }, String.valueOf(i)).start();
        }
        new HashSet().add("a");
    }

四、集合不安全类之Map 4.1 代码示例
    public static void main(String[] args) {
        //Map map = new HashMap();
        Map map = new ConcurrentHashMap(); //Collections.synchronizedMap();
        for (int i = 1; i  {
                map.put(Thread.currentThread().getName(), UUID.randomUUID().toString().substring(0, 8));
                System.out.println(map);
            }, String.valueOf(i)).start();
        }
    }

4.2 总结

解决并发情况下的线程安全问题

List线程:CopyOnWriteArrayList

Set线程:CopyOnWriteHashSet

Map线程:ConcurrentHashMap

集合的全部讲解代码

public class ContainerNotSafeDemo {
    public static void main(String[] args) {
        Map map =new  ConcurrentHashMap();
        for (int i = 1; i  {
                map.put(Thread.currentThread().getName(),UUID.randomUUID().toString().substring(0, 8));
                System.out.println(map);
            }, String.valueOf(i)).start();
        }
    }

    private static void setNotSafe() {
        Set set = new CopyOnWriteArraySet();
        for (int i = 1; i  {
                set.add(UUID.randomUUID().toString().substring(0, 8));
                System.out.println(set);
            }, String.valueOf(i)).start();
        }
    }

    private static void listNotSafe() {
        List list = new CopyOnWriteArrayList();  //写时复制技术
        for (int i = 1; i {
                list.add(UUID.randomUUID().toString().substring(0,8));
                System.out.println(list);
            },String.valueOf(i)).start();
        }
    }
}

视频教程,源码

关注
打赏
1636984416
查看更多评论
立即登录/注册

微信扫码登录

0.1439s