MST

星途 面试题库

面试题:Java并发集合类的线程安全机制

以CopyOnWriteArrayList为例,详细说明Java并发集合类是如何实现线程安全的,包括读写操作的具体实现方式,以及这种实现方式对性能和内存的影响。
49.6万 热度难度
编程语言Java

知识考点

AI 面试

面试题答案

一键面试

1. CopyOnWriteArrayList线程安全实现原理

CopyOnWriteArrayList通过“写时复制”机制实现线程安全。当进行写操作(如add、remove等)时,会创建底层数组的一个副本,在副本上进行修改,完成后再将原数组引用指向新的副本。而读操作(如get等)则直接读取原数组,不进行加锁操作。

2. 读写操作具体实现方式

  • 写操作
    • add(E e)方法为例,其实现如下:
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(int index)方法为例:
public E get(int index) {
    return get(getArray(), index);
}
private E get(Object[] a, int index) {
    return (E) a[index];
}
- 直接从数组中获取元素,没有加锁操作。

3. 对性能和内存的影响

  • 性能
    • 读性能:读操作性能高,因为无需加锁,适合读多写少的场景。多个线程可以并发进行读操作,不会发生竞争。
    • 写性能:写操作性能相对较低,因为每次写操作都要复制数组,这涉及内存分配和数据复制,开销较大。同时,写操作时会加锁,限制了写操作的并发度。
  • 内存
    • 由于写操作需要复制数组,在写操作频繁时,会占用更多的内存空间。如果数组元素较多,每次复制产生的新数组会导致内存使用量显著增加。在写操作完成前,新旧数组同时存在于内存中,可能会引发内存压力甚至内存溢出问题。