> 文档中心 > 集合类不安全之并发修改异常与写时复制

集合类不安全之并发修改异常与写时复制

我们知道ArrayList是线程不安全,请编码写一个不安全的案例并给出解决方案

/**集合不安全的问题*/public class ContainerNotSafeDemo{    public static void main(String[] args){        //new ArrayList().add(1);底层创建一个长度为10的object数组,满了之后扩容变成原来的1.5倍        //List list = Arrays.asList("a", "b", "c");        //list.forEach(System.out::println);        List list = Collections.synchronizedList(new ArrayList());        for(int i = 1; i <= 3; i++){            List list = new ArrayList();            for(int i = 1; i  {                    list.add(UUID.randomUUID().toString().substring(0, 8));                    System.out.println(list);//可能会打出null或者数量不对 线程数更多的话还会报错java.util.ConcurrentModificationException                },String.valueOf(i)).start();                /**                 不要只是会用,会用只不过是一个API调用工程师  底层原理                1. 故障现象 java.util.ConcurrentModificationException                2. 导致原因                    并发争抢修改导致,参考我们的花名册签名情况。                    一个人正在写入,另外一个同学过来争抢,导致数据不一致异常。并发修改异常                3. 解决方案                 3.1 vector();                 3.2 Collections.synchronizedList(new ArrayList());                 3.3 new CopyOnWriteArrayList();                4. 优化建议(同样的错误不犯第2次)                */            }        }    }}

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

public boolean add(E e){    final ReentrantLock lock = this,lock;    lock.lock();    try{        Object[] elements = getArray();        int len = elements.length;        Object[] newElements = Arrays.copyOf(elements, len+1);        newElements[Len] = e;        setArray(newElements);        return true;    }finally{        lock.unlock();    }}

HashSet底层是使用初始容量(initial capacity)为16,负载因子(load factory)为0.75的HashMap,并且键就是map中的键,值就是一个Object的PRESENT常量

public HashSet(){    map = new HashMap();}​private static final Object PRESENT = new Object();​public boolean add(E e){    return map.put(e.PRESENT)==null;}