【java集合】多线程场景下使用 ArrayList(含源码解析)

大家好,我是walker
一个从文科自学转行的程序员~
爱好编程,偶尔写写编程文章和生活
欢迎关注公众号【I am Walker】,一块学习编程~

ArrayList应该是我们比较常用的集合了,在一般场景下使用是没有问题的,
但是如果在多线程场景下,应该怎么使用呢?
主要有两种方式,如下:

方式一:使用Collections.synchronizedList()

ArrayList 不是线程安全的,如果遇到多线程场景,
可以通过 Collections 的 synchronizedList 方法将其转换成线程安全的容器后再使用。
案例:

    public void testSynchronizedArrayList(){
        ArrayList<String> arrayList = new ArrayList<String>();
        arrayList.add("a");
        List<String> synchronizedList = Collections.synchronizedList(arrayList);
        synchronizedList.add("a");
    }
Collections.synchronizedList源码
    public static <T> List<T> synchronizedList(List<T> list) {
        //判断数组是否实现了RandomAccess,如果是选择创建SynchronizedRandomAccessList对象
        //否则则创建SynchronizedList对象
        return (list instanceof RandomAccess ?
                new SynchronizedRandomAccessList<>(list) :
                new SynchronizedList<>(list));
    }
SynchronizedRandomAccessList
        SynchronizedRandomAccessList(List<E> list) {
            super(list);
        }
SynchronizedList
SynchronizedList(List<E> list) {
            super(list);
            this.list = list;
        }
SynchronizedCollection
        final Object mutex;     // Object on which to synchronize

SynchronizedCollection(Collection<E> c) {
            this.c = Objects.requireNonNull(c);
            mutex = this;
        }

然后其对应的add方法

add
        final Object mutex;   //对mutex对象进行加锁,而不是对整个方法进行加锁,锁的粒度下降,效率提高
        final Collection<E> c;

public boolean add(E e) {
            synchronized (mutex) {return c.add(e);}
        }

方式二:使用CopyOnWriteArrayList

copyOnWriteArrayList相当于每次使用都会复制一份新的ArrayList
保证隔离,这样子线程使用就安全了,但是有个缺点,就是比较费内存,而且如果是增删改场景较多的时候,数组复制会浪费较多的时间

    public void testCopyOnWrite(){
        CopyOnWriteArrayList<String> copyOnWriteArrayList = new CopyOnWriteArrayList<>();
        copyOnWriteArrayList.add("a");
    }
CopyOnWriteArrayList.add源码
    final transient ReentrantLock lock = new ReentrantLock(); //可冲入锁

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);
            //赋值,最后一个下标赋值为e
            newElements[len] = e;
            //重新设置数组元素
            setArray(newElements);
            return true;
        } finally {
            //解锁
            lock.unlock();
        }
    }
getArray
    private transient volatile Object[] array; //使用了volatile 保证可见性和防止指令重排

final Object[] getArray() {
        return array;
    }
setArray
    final void setArray(Object[] a) {
        array = a;
    }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

WalkerShen

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值