栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

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

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

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

目录

一、集合类ArrayList线程不安全的代码示例二、集合类ArrayList线程不安全的故障现象三、集合类ArrayList线程不安全的原因四、集合类ArrayList线程不安全的解决方案

4.1、解决方式一:通过vector集合类解决(不建议)4.2、解决方式二:通过Collections工具类解决4.3、解决方式三:通过JUC包下的写时复制集合类解决 五、CopyOnWriteArrayList线程安全的源码解析

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

代码

import java.util.ArrayList;
import java.util.UUID;

public class ContainerNotSafe {
    public static void main(String[] args) {
        ArrayList list = new ArrayList<>();
        //模拟10个线程,往ArrayList集合中添加数据
        for(int i=1;i<=10;i++){
            new Thread(()->{
                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.*;

public class ContainerNotSafe {
    public static void main(String[] args) {
        Vector list = new Vector<>();
        //模拟10个线程,往Vector集合中添加数据
        for(int i=1;i<=10;i++){
            new Thread(()->{
                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.*;

public class ContainerNotSafe {
    public static void main(String[] args) {
        List list=Collections.synchronizedList(new ArrayList<>());
        //模拟10个线程,往synchronizedList集合中添加数据
        for(int i=1;i<=10;i++){
            new Thread(()->{
                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;

public class ContainerNotSafe {
    public static void main(String[] args) {
        List list=new CopyOnWriteArrayList<>();
        //模拟10个线程,往ArrayList集合中添加数据
        for(int i=1;i<=10;i++){
            new Thread(()->{
                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容器也是一种读写分离的思想,读和写不同的容器。

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/703191.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号