• ArrayList线程不安全解决办法


    先给出不安全的代码:

    public static void main(String[] args) {
        //List list = Collections.synchronizedList(new ArrayList<>());
        List list = new ArrayList();
        for(int i = 0; i < 30; i++){
            new Thread(()->{
                list.add(UUID.randomUUID().toString().substring(0,8));
                System.out.println(Thread.currentThread().getName()+"\t"+list.toString());
                //System.out.println(list.toString());
            },"thread: "+i).start();
        }
    }

    运行完,控制台报错如下:

    报了并发修改异常。 

    给出解决办法:

    1.使用new Vector<>();进行替换(源码内部加锁synchronized线程安全,效率低)

    2.使用Collections工具类中的synchronizedList()方法,代码如下:

    List list = Collections.synchronizedList(new ArrayList<>());

    示例代码:

    public static void main(String[] args) {
        List list = Collections.synchronizedList(new ArrayList<>());
        //List list = new ArrayList();
        for(int i = 0; i < 30; i++){
            new Thread(()->{
                list.add(UUID.randomUUID().toString().substring(0,8));
                System.out.println(Thread.currentThread().getName()+"\t"+list.toString());
                //System.out.println(list.toString());
            },"thread: "+i).start();
        }
    }

    同时Collections还提供了synchronizedMap()、synchronizedSet()等方法。

    3.使用JUC中的CopyOnWriteArrayList<>();

    new CopyOnWriteArrayList<>();原理:写时复制技术。

    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;
                // 1、将内容复制了一份
                Object[] newElements = Arrays.copyOf(elements, len + 1);
                // 2、写入新的内容
                newElements[len] = e;
                // 3、合并
                setArray(newElements);
                return true;
            } finally {
                lock.unlock();
            }
        }
     

  • 相关阅读:
    MySQL
    从零开始搭建oj(ubuntu)
    QT 自学内容 day05 自定义的控件封装,定时器的两种使用方法,event 事件分发器,事件过滤器!
    Squirrel可视化连接Phoenix_尚硅谷大数据培训
    成为会带团队的技术人 架构设计:治理好系统复杂度才最务实
    ABAP BAPI_ACC_DOCUMENT_POST 中 EXTENSION1的用法
    李m圆申论
    小文件存到HDFS占用空间是文件实际大小,而非一个block块的大小
    ubuntu 安装 gparted
    逆向WeChat(三)
  • 原文地址:https://blog.csdn.net/qq_36743013/article/details/126052057