08 CopyOnWriteArrayList

jdk 基于 8 版本

在平时的开发中,我们经常会用到 CopyOnWriteArrayList, 利用写时复制的机制来保证并发安全, 适合多读少写的场景。

使用方式

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
public class CopyOnWriteArrayListTest {

    @Test
    public void test() {
        List<String> data = new CopyOnWriteArrayList<>();
        data.add("1");
        assertThat(data.get(0)).isEqualTo("1");
        data.remove("1");
        assertThat(data.isEmpty()).isEqualTo(true);
    }
}

add

添加元素,写时复制

源码位置: java.util.concurrent.CopyOnWriteArrayList#add(E)

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
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();
    }
}

get

获取元素,不加锁。

源码位置: java.util.concurrent.CopyOnWriteArrayList#get(int)

1
2
3
4
public E get(int index) {
    // 获取数据,这里不加锁
    return get(getArray(), index);
}

remove

删除元素,写时复制

源码位置: java.util.concurrent.CopyOnWriteArrayList#remove(int)

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
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();
    }
}
0%