您当前的位置: 首页 >  Java

小志的博客

暂无认证

  • 1浏览

    0关注

    1217博文

    0收益

  • 0浏览

    0点赞

    0打赏

    0留言

私信
关注
热门博文

Java并发多线程编程——集合类线程不安全之ArrayList的示例及解决方案

小志的博客 发布时间:2022-01-11 22:25:07 ,浏览量:1

目录
    • 一、集合类ArrayList线程不安全的代码示例
    • 二、集合类ArrayList线程不安全的故障现象
    • 三、集合类ArrayList线程不安全的原因
    • 四、集合类ArrayList线程不安全的解决方案
      • 4.1、解决方式一:通过vector集合类解决(不建议)
      • 4.2、解决方式二:通过Collections工具类解决
      • 4.3、解决方式三:通过JUC包下的写时复制集合类解决
    • 五、CopyOnWriteArrayList线程安全的源码解析

一、集合类ArrayList线程不安全的代码示例
  • 代码

    import java.util.ArrayList;
    import java.util.UUID;
    /**
     * @description: ArrayList线程不安全的代码示例
     * @author: xz
     */
    public class ContainerNotSafe {
        public static void main(String[] args) {
            ArrayList list = new ArrayList();
            //模拟10个线程,往ArrayList集合中添加数据
            for(int i=1;i{
                    list.add(UUID.randomUUID().toString().substring(0,8));
                    System.out.println(list);
                }).start();
            }
    
        }
    }
    
  • 输出结果如下: 在这里插入图片描述

二、集合类ArrayList线程不安全的故障现象
  • 报 java.util.ConcurrentModificationException 异常错误 在这里插入图片描述
三、集合类ArrayList线程不安全的原因
  • 并发争抢修改导致报 java.util.ConcurrentModificationException 异常错误。
四、集合类ArrayList线程不安全的解决方案 4.1、解决方式一:通过vector集合类解决(不建议)
  • 代码

    import java.util.*;
    /**
     * @description: 通过vector集合类解决集合类ArrayList线程不安全问题
     * @author: xz
     */
    public class ContainerNotSafe {
        public static void main(String[] args) {
            Vector list = new Vector();
            //模拟10个线程,往Vector集合中添加数据
            for(int i=1;i{
                    list.add(UUID.randomUUID().toString().substring(0,8));
                    System.out.println(list);
                }).start();
            }
    
        }
    }
    
  • 输出结果如下: 在这里插入图片描述

  • 不建议使用vector集合类解决的原因

    (1)、Vector集合类于JDK1.0版本出现,Vector通过加锁的方式实现,保证了数据一致性,但是并发性下降。 在这里插入图片描述

    (2)、ArrayList集合类于JDK1.2版本出现。ArrayList为了杜绝了Vector的情况,是一种不加锁的集合类,并发性加强,但是不保证线程的安全性。 在这里插入图片描述

4.2、解决方式二:通过Collections工具类解决
  • 代码

    import java.util.*;
    /**
     * @description: 通过Collections工具类解决集合类ArrayList线程不安全问题
     * @author: xz
     */
    public class ContainerNotSafe {
        public static void main(String[] args) {
            List list=Collections.synchronizedList(new ArrayList());
            //模拟10个线程,往synchronizedList集合中添加数据
            for(int i=1;i{
                    list.add(UUID.randomUUID().toString().substring(0,8));
                    System.out.println(list);
                }).start();
            }
    
        }
    }
    
  • 输出结果如下: 在这里插入图片描述

4.3、解决方式三:通过JUC包下的写时复制集合类解决
  • jdk1.8 API中的写时复制集合类截图如下: 在这里插入图片描述

  • 代码

    import java.util.*;
    import java.util.concurrent.CopyOnWriteArrayList;
    /**
     * @description: 通过JUC包下的写时复制集合类解决ArrayList线程不安全问题
     * @author: xz
     */
    public class ContainerNotSafe {
        public static void main(String[] args) {
            List list=new CopyOnWriteArrayList();
            //模拟10个线程,往ArrayList集合中添加数据
            for(int i=1;i{
                    list.add(UUID.randomUUID().toString().substring(0,8));
                    System.out.println(list);
                }).start();
            }
    
        }
    }
    
  • 输出结果如下: 在这里插入图片描述

五、CopyOnWriteArrayList线程安全的源码解析
  • 源码如下

    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();
        }
    }
    
  • 源码截图如下 在这里插入图片描述

  • 【源码的理解】

  • 写时复制 (copyOnWrite容器 )即写时复制的容器, 往容器添加元素的时候,不直接往当前容器object[]添加,而是先将当前容器object[]进行copy 复制出一个新的object[] newElements ,然后向新容器object[] newElements 里面添加元素 ;

  • 添加元素后再将原容器的引用指向新的容器 setArray(newElements);

  • 这样的好处是可以对copyOnWrite容器进行并发的读,而不需要加锁, 因为当前容器不会添加任何容器。所以copyOnwrite容器也是一种读写分离的思想,读和写不同的容器。

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

微信扫码登录

0.0465s