CopyOnWriteArrayList
- CopyOnWriteArrayList适合于多线程场景下使用,其采用读写分离的思想,读操作不上锁,写操作上锁,且写操作效率较低。
- CopyOnWriteArrayList基于fail-safe机制,每次修改都会在原先基础上复制一份,修改完毕后在进行替换。
- CopyOnWriteArrayList采用的是ReentrantLock进行上锁。
- CopyOnWriteArrayList和ArrayList一样,其底层数据结构也是数组,加上transient不让其被序列化,加上volatile修饰来保证多线程下的其可见性和有序性。
- CopyOnWriteArrayList效率比ArrayList低不少,毕竟多线程场景下,其每次都是要在原数组基础上复制一份在操作耗内存和时间,而ArrayList只是容量满了进行扩容,因此在非多线程的场景下还是用ArrayList吧。
构造函数
| public CopyOnWriteArrayList() { |
| |
| setArray(new Object[0]); |
| } |
| |
| final void setArray(Object[] a) { |
| array = a; |
| } |
| |
| public CopyOnWriteArrayList(Collection<? extends E> c) { |
| Object[] elements; |
| |
| if (c.getClass() == CopyOnWriteArrayList.class) |
| elements = ((CopyOnWriteArrayList<?>)c).getArray(); |
| else { |
| |
| elements = c.toArray(); |
| |
| if (elements.getClass() != Object[].class) |
| elements = Arrays.copyOf(elements, elements.length, Object[].class); |
| } |
| |
| setArray(elements); |
| } |
| |
| public CopyOnWriteArrayList(E[] toCopyIn) { |
| |
| setArray(Arrays.copyOf(toCopyIn, toCopyIn.length, Object[].class)); |
| } |
读取方法(未加锁)
| final Object[] getArray() { |
| return array; |
| } |
| public int size() { |
| return getArray().length; |
| } |
| public boolean isEmpty() { |
| return size() == 0; |
| } |
| public int indexOf(E e, int index) { |
| Object[] elements = getArray(); |
| return indexOf(e, elements, index, elements.length); |
| } |
| public int lastIndexOf(Object o) { |
| Object[] elements = getArray(); |
| return lastIndexOf(o, elements, elements.length - 1); |
| } |
| |
| ........ |
add方法(使用ReentrantLock加锁)
| 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(); |
| } |
| } |
可见其修改操作是基于fail-safe机制,像我们的String一样,不在原来的对象上直接进行操作,而是复制一份对其进行修改,另外此处的修改操作是利用Lock锁进行上锁的,所以保证了线程安全问题。
remove方法(使用ReentrantLock加锁)
| public boolean remove(Object o) { |
| Object[] snapshot = getArray(); |
| int index = indexOf(o, snapshot, 0, snapshot.length); |
| return (index < 0) ? false : remove(o, snapshot, index); |
| } |
| |
| private boolean remove(Object o, Object[] snapshot, int index) { |
| final ReentrantLock lock = this.lock; |
| |
| lock.lock(); |
| try { |
| Object[] current = getArray(); |
| int len = current.length; |
| if (snapshot != current) findIndex: { |
| int prefix = Math.min(index, len); |
| for (int i = 0; i < prefix; i++) { |
| if (current[i] != snapshot[i] && eq(o, current[i])) { |
| index = i; |
| break findIndex; |
| } |
| } |
| if (index >= len) |
| return false; |
| if (current[index] == o) |
| break findIndex; |
| index = indexOf(o, current, index, len); |
| if (index < 0) |
| return false; |
| } |
| |
| Object[] newElements = new Object[len - 1]; |
| System.arraycopy(current, 0, newElements, 0, index); |
| System.arraycopy(current, index + 1, |
| newElements, index, |
| len - index - 1); |
| |
| setArray(newElements); |
| return true; |
| } finally { |
| lock.unlock(); |
| } |
| } |
思路与add方法一致。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· SQL Server 2025 AI相关能力初探
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南