解决方案:

1、切换成Vector就是线程安全的啦!

public class ListTest {
    public static void main(String[] args) {
        List<Object> arrayList = new Vector<>();
    }
}

Vector的add方法,Vector比ArrayList更早出现,所以Vector只是其中一种解决办法

java怎么保证ArrayList线程安全 怎么让arraylist线程安全_List

2、使用工具类 Collections.synchronizedList(new ArrayList<>());

public class ListTest {
    public static void main(String[] args) {

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

    }
}

3、使JUC中的包:List arrayList = new CopyOnWriteArrayList<>();

public class ListTest {
    public static void main(String[] args) {

        List<Object> arrayList = new CopyOnWriteArrayList<>();

    }
}

CopyOnWriteArrayList:写入时复制! COW 计算机程序设计领域的一种优化策略 ,提高效率

多个线程调用的时候,list,读取的时候,是固定的,写入(存在覆盖操作);在写入的时候避免覆盖,造成数据错乱的问题;

CopyOnWriteArrayList比Vector厉害在哪里?

Vector 底层是使用synchronized关键字来实现的:效率特别低下。

CopyOnWriteArrayList 使用的是Lock锁,效率会更加高效!

java怎么保证ArrayList线程安全 怎么让arraylist线程安全_java_02

  • CopyOnWriteArrayList是一个线程安全的ArrayList,其实现原理是读写分离
其对写操作使用`ReentrantLock`来上锁,对读操作则不加锁;
CopyOnWriteArrayList在写操作的时候,会将list中的数组拷贝一份副本,然后对其副本进行操作(如果此时其他线程需要读的事,那么其他线程读取的是原先的没有修改的数组
如果其他写操作的线程要进行写操作,需要等待正在写的线程操作完成,释放ReentrantLock后,去获取锁才能进行写操作),写操作完成后,会将list中数组的地址引用指向修改后的新数组地址
如果使用场景的写操作十分频繁的话,建议还是不要实现CopyOnWriteArrayList,因为其添加的时候会造成数组的不断扩容和复制,十分消耗性能,会消耗内存
如果原数组的数据比较多的情况下,可能会导致young gc或者full gc;并且其不能使用在实时读的场景,在写操作过程中是要花费时间的,读取的时候可能还是旧数据;
CopyOnWriteArrayList 合适读多写少的场景
如果我们在使用的时候没法保证CopyOnWriteArrayList 到底要放多少数据的话,我们还是要谨慎使用,如果数据稍微有点多,每次写操作都重新拷贝数组,其代价实在太高昂了