为什么有了并发安全的集合还需要读写锁?(一)

pivoteic
发布于 2022-6-16 17:48
浏览
0收藏

 

大家好,我是三友,这篇文章想来跟大家来探讨一下,在Java中已经提供了并发安全的集合,为什么有的场景还需要使用读写锁,直接用并发安全的集合难道不行么?

 

在java中,并发安全的集合有很多,这里我就选用常见的CopyOnWriteArrayList为例,来说明一下读写锁的价值到底提现在哪。

 

CopyOnWriteArrayList核心源码分析

 

接下来我们分析一下CopyOnWriteArrayList核心的增删改查的方法

 

成员变量

//独占锁
final transient ReentrantLock lock = new ReentrantLock();
//底层用来存放元素的数组
private transient volatile Object[] array;


add方法:往集合中添加某个元素

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();
        }
    }


add操作先通过lock加锁,保证同一时刻最多只有一个线程可以操作。加锁成功获取到成员变量的数据,然后拷贝成员变量数组的元素到新的数组,再基于新的数据来添加元素,最后将新拷贝的数组通过setArray来替换旧的成员变量的数组。

 

remove方法:移除集合中的某个元素

public E remove(int index) {
        final ReentrantLock lock = this.lock;
        lock.lock();
        try {
            Object[] elements = getArray();
            int len = elements.length;
            E oldValue = get(elements, index);
            int numMoved = len - index - 1;
            if (numMoved == 0)
                setArray(Arrays.copyOf(elements, len - 1));
            else {
                Object[] newElements = new Object[len - 1];
                System.arraycopy(elements, 0, newElements, 0, index);
                System.arraycopy(elements, index + 1, newElements, index,
                                 numMoved);
                setArray(newElements);
            }
            return oldValue;
        } finally {
            lock.unlock();
        }
    }


remove操作也要先获取到锁。它先是取出对应数组下标的旧元素,然后新建了一个原数组长度减1的新数组,将除了被移除的元素之外,剩余的元素拷贝到新的数组,最后再通过setArray替换旧的成员变量的数组。

 

set方法:将集合中指定位置的元素替换成新的元素

public E set(int index, E element) {
        final ReentrantLock lock = this.lock;
        lock.lock();
        try {
            Object[] elements = getArray();
            E oldValue = get(elements, index);

            if (oldValue != element) {
                int len = elements.length;
                Object[] newElements = Arrays.copyOf(elements, len);
                newElements[index] = element;
                setArray(newElements);
            } else {
                // Not quite a no-op; ensures volatile write semantics
                setArray(elements);
            }
            return oldValue;
        } finally {
            lock.unlock();
        }
    }


文章转自公众号:三友的java日记

标签
已于2022-6-16 17:48:08修改
收藏
回复
举报
回复
    相关推荐