我是靠谱客的博主 俏皮楼房,这篇文章主要介绍java.util.concurrent.CopyOnWriteArrayList,现在分享给大家,希望可以做个参考。

 

CopyOnWriteArrayList

CopyOnWriteArrayList是一个线程安全、并且在读操作时无锁的ArrayList。

1)添加

add(E e)

复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
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(); } }

这里同样没有使用synchronized关键字,而是使用ReentrantLock。

和ArrayList不同的是,这里每次都会创建一个新的object数组,大小比之前数组大1。将之前的数组复制到新数组,并将新加入的元素加到数组末尾。

2)删除

remove(Object o)

复制代码
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
28
29
30
31
32
public boolean remove(Object o) { final ReentrantLock lock = this.lock; lock.lock(); try { Object[] elements = getArray(); int len = elements.length; if (len != 0) { // Copy while searching for element to remove // This wins in the normal case of element being present int newlen = len - 1; Object[] newElements = new Object[newlen];//新建数组 for (int i = 0; i < newlen; ++i) { if (eq(o, elements[i])) { // found one; copy remaining and exit for (int k = i + 1; k < len; ++k) newElements[k-1] = elements[k]; setArray(newElements); return true; } else newElements[i] = elements[i]; } // special handling for last cell if (eq(o, elements[newlen])) { setArray(newElements); return true; } } return false; } finally { lock.unlock(); } }

此方法为什么这么直接进行数组的复制呢?为何不适用system的arrayCopy来完成?

3)获取

get(int index)

复制代码
1
2
3
public E get(int index) { return (E)(getArray()[index]); }

这里有可能脏读。但是销量非常高。

//通过看集合包和并发包可以看出一些不同的编程思路。这里为什么就不事先做范围的检查?

从上可见,CopyOnWriteArrayList基于ReentrantLock保证了增加元素和删除元素动作的互斥。在读操作上没有任何锁,这样就保证了读的性能,带来的副作用是有时候可能会读取到脏数据。

 

既然这样的话,应用的场景在哪呢?知道的朋友请告诉我一下。

 

补充:

CopyOnWriteArrayList 和 CopyOnWriteArraySet

可以用两种方法创建线程安全支持数据的 List -- Vector 或封装 ArrayListCollections.synchronizedList()java.util.concurrent 包添加了名称繁琐的 CopyOnWriteArrayList。为什么我们想要新的线程安全的 List 类?为什么 Vector 还不够?

最简单的答案是与迭代和并发修改之间的交互有关。使用 Vector 或使用同步的 List 封装器,返回的迭代器是 fail-fast 的,这意味着如果在迭代过程中任何其他线程修改 List,迭代可能失败。

Vector 的非常普遍的应用程序是存储通过组件注册的监听器的列表。当发生适合的事件时,该组件将在监听器的列表中迭代,调用每个监听器。为了防止 ConcurrentModificationException,迭代线程必须复制列表或锁定列表,以便进行整体迭代,而这两种情况都需要大量的性能成本。

CopyOnWriteArrayList 类通过每次添加或删除元素时创建支持数组的新副本,避免了这个问题,但是进行中的迭代保持对创建迭代器时的当前副本进行操作。虽然复制也会有一些成本,但是在许多情况下,迭代要比修改多得多,在这些情况下,写入时复制要比其他备用方法具有更好的性能和并发性。

如果应用程序需要 Set 语义,而不是 List,那么还有一个 Set 版本 -- CopyOnWriteArraySet

最后

以上就是俏皮楼房最近收集整理的关于java.util.concurrent.CopyOnWriteArrayList的全部内容,更多相关java内容请搜索靠谱客的其他文章。

本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
点赞(80)

评论列表共有 0 条评论

立即
投稿
返回
顶部