我是靠谱客的博主 俏皮楼房,最近开发中收集的这篇文章主要介绍java.util.concurrent.CopyOnWriteArrayList,觉得挺不错的,现在分享给大家,希望可以做个参考。

概述

 

CopyOnWriteArrayList

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

1)添加

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();
}
}

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

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

2)删除

remove(Object o)

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)

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.util.concurrent.CopyOnWriteArrayList所遇到的程序开发问题。

如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。

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

评论列表共有 0 条评论

立即
投稿
返回
顶部