本文共 1758 字,大约阅读时间需要 5 分钟。
CopyOnWriteArrayList:线程安全的 Java List
作为一名程序员,我在一次面试中遇到了一个让人难忘的经历。面试官老马问我 ArrayList 是否线程安全,我当时被问出了Vector和CopyOnWriteArrayList,这场面试让我深刻认识到线程安全的重要性。现在,我将从这些经历中总结出关于CopyOnWriteArrayList的真知灼见。
Vector:线程安全的代价
Vector 是 Java 中最早的线程安全 List,所有方法都加上了 synchronized 关键字。然而,这种锁粒度很高,性能表现不佳。在高并发场景下,Vector 的线程安全确实可靠,但其资源占用和性能开销让它逐渐被淘汰。
public synchronized boolean add(E e) { modCount++; add(e, elementData, elementCount); return true;} SynchronizedList:传统的线程安全实现
有些开发者会使用 Collections.synchronizedList() 将 ArrayList 转换为线程安全的集合。这种方法通过在方法体内加锁实现线程安全,但锁粒度较大,性能表现依然不理想。
public void add(int index, E element) { synchronized (mutex) { list.add(index, element); }} ConcurrentModificationException:失败快的迭代器
在 Java 中,迭代器默认是 fail-fast 的。如果在遍历时对集合进行修改操作,会抛出 ConcurrentModificationException。这种机制在多线程环境下确保了数据的一致性,但也限制了并发操作的灵活性。
public void fastRemove(Object[] es, int i) { modCount++; final int newSize; if ((newSize = size - 1) > i) System.arraycopy(es, i + 1, es, i, newSize - i); es[size = newSize] = null;} CopyOnWriteArrayList:面试官的秘密武器
CopyOnWriteArrayList 是 Java 提供的线程安全 List,通过复制数组实现线程安全。在写操作时,会创建一个新的数组进行修改,最后将新数组替换原数组。这种机制使得读操作不需要加锁,写操作则通过锁保护。
public boolean add(E e) { synchronized (lock) { Object[] es = getArray(); int len = es.length; es = Arrays.copyOf(es, len + 1); es[len] = e; setArray(es); return true; }} 读写分离的优势
CopyOnWriteArrayList 的写操作加锁,读操作不加锁。这种设计允许多线程环境下读写并行,但写操作必须等待锁。这使得 CopyOnWriteArrayList 在单线程环境下表现尤其优异,适合大多数应用场景。
选择 CopyOnWriteArrayList
在选择线程安全的 List 时,CopyOnWriteArrayList 是一个理想的选择。当需要线程安全但不需要过多的锁开销时,它是最优的选择。然而,在读操作频繁且写操作较少的场景下,可能会因为数组复制操作带来的性能开销而感到不爽。
结语
从 Vector 到 CopyOnWriteArrayList,这些线程安全的 List 实现都有其独特的特点和适用场景。了解这些实现的原理,是成为一名优秀开发者的必修课。希望这篇文章能帮助你在面试中脱颖而出,成为技术大牛!
发表评论
最新留言
关于作者