java - 为 CopyOnWriteArrayList 中的添加操作获取锁

标签 java multithreading reentrantlock

为什么我们在List中添加元素时需要按照CopyOnWriteArrayList中的以下代码获取Reentrant锁。我们正在创建原始数组的副本,然后对其进行修改。如果我们不首先获取 ,我们会有什么副作用?

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

最佳答案

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

这里 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) 创建新数组,并将变量 e 的值赋给新数组的 len 位置。

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

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

关于java - 为 CopyOnWriteArrayList 中的添加操作获取锁,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/55667259/

相关文章:

java - 带有 JPA 的 GWT - 没有持久性提供者

java.sql.SQLException : No suitable driver found for jdbc:mariadb in a Gradle project (Intellij)

java - ScheduledThreadPoolExecutor 任务从队列中移除

java - 为什么不允许 ReadWriteLock 升级?

java - 如果同一个线程一次又一次地获取锁,ReentrantLock 如何公平?

java - 如何使用NamedParameterJdbcTemplate检索Decimal(4,2)

java - 循环不会添加总计

java : Is Thread priority changed by JVM(implicitly)

c++ - LeakSanitizer : get run time leak reports?

java - ReentrantLock 在同一个线程中被神秘地解锁,即使没有其他线程正在访问它