首页 > 解决方案 > 在 CopyOnWriteArrayList 中获取添加操作的锁

问题描述

为什么我们在添加元素时需要Reentrant按照下面的代码获取锁。我们正在创建原始数组的副本,然后对其进行修改。如果我们一开始就没有获得,我们会有什么副作用?CopyOnWriteArrayListListlock

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

标签: javamultithreadingreentrantlock

解决方案


当您尝试在多线程上下文中对全局变量执行任何操作并希望它是原子的并确保对其他线程的内存可见性时,您需要对该操作进行锁定。

这里getArray()返回一个全局实例字段Object[] array

所以在这个例子中:

Object[] elements = getArray();
int len = elements.length;
Object[] newElements = Arrays.copyOf(elements, len + 1);
newElements[len] = e;
setArray(newElements);
return true;

如果这个代码块周围没有锁,并且假设两个线程正在尝试添加一个元素,那么在这种情况下,线程一和线程二可能都会读取相同的值len并将新元素分配给相同的索引。

因此,哪个线程在最后分配新值将覆盖另一个线程之前设置的值。

为了进一步解释,假设线程一和线程二都读取了相同的值,len现在线程一继续创建新数组Arrays.copyOf(elements, len + 1),并将变量的值分配到新数组elen位置。

在线程一可以使用setArray(newElements)线程二设置新数组之前,同时使用相同的值继续这个过程len。虽然它会创建一个新的数组实例,但设置新元素的索引将与len线程一使用的索引相同。

因此,当线程二setArray(newElements)在线程一之后使用新值设置新数组时,len第 th索引处较早的数组值将被线程二设置的新元素覆盖。


推荐阅读