根据我的理解,并发集合类优先于同步集合,因为并发集合类不会锁定整个集合对象.相反,他们会对集合对象的一小部分进行锁定.
但是当我检查add
方法时CopyOnWriteArrayList
,我们正在获取完整集合对象的锁定.那么为什么CopyOnWriteArrayList
比返回的列表更好Collections.synchronizedList
?我在add
方法中看到的唯一区别CopyOnWriteArrayList
是每次add
调用方法时我们都在创建该数组的副本.
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();
}
}
Run Code Online (Sandbox Code Playgroud)
Stu*_*rks 12
根据我的理解,并发集合类优先于同步集合,因为并发集合类不会锁定完整的集合对象.相反,它会锁定集合对象的小段.
对于某些集合而言并非如此.通过Collections.synchronizedMap
在每个操作周围锁定整个映射而返回的映射,而ConcurrentHashMap
对于某些操作仅锁定一个散列桶,或者对于其他操作可能使用非阻塞算法.
对于其他集合,使用的算法以及因此的权衡是不同的.对于通过Collections.synchronizedList
比较返回的列表尤其如此CopyOnWriteArrayList
.正如你提到的,都synchronizedList
和CopyOnWriteArrayList
走在写操作在整个阵列上的锁.那为什么不同呢?
如果您查看其他操作,例如迭代集合的每个元素,就会出现差异.文件Collections.synchronizedList
说,
当迭代它时,用户必须手动同步返回的列表:
List list = Collections.synchronizedList(new ArrayList());
...
synchronized (list) {
Iterator i = list.iterator(); // Must be in synchronized block
while (i.hasNext())
foo(i.next());
}
Run Code Online (Sandbox Code Playgroud)
不遵循此建议可能会导致非确定性行为.
换句话说,迭代一个synchronizedList
是不是线程安全的,除非你手动锁.请注意,使用此技术时,此列表中其他线程的所有操作(包括迭代,获取,设置,添加和删除)都将被阻止.一次只有一个线程可以对此集合执行任何操作.
相比之下,文件CopyOnWriteArrayList
说,
"快照"样式迭代器方法在创建迭代器时使用对数组状态的引用.这个数组在迭代器的生命周期中永远不会改变,所以干扰是不可能的,并且保证迭代器不会抛出
ConcurrentModificationException
.自迭代器创建以来,迭代器不会反映列表的添加,删除或更改.
此列表上的其他线程的操作可以同时进行,但迭代不受任何其他线程所做更改的影响.因此,即使写入操作锁定整个列表,CopyOnWriteArrayList
仍然可以提供比普通列表更高的吞吐量synchronizedList
.(只要读取和遍历的比例很高.)
1)get和其他读操作CopyOnWriteArrayList
不同步.
2)CopyOnWriteArrayList
迭代器永远不会,throws ConcurrentModificationException
而Collections.synchronizedList
迭代器可能会抛出它.
对于写入(添加)操作,CopyOnWriteArrayList使用ReentrantLock并创建数据的备份副本,并且仅通过setArray更新基础易失性数组引用(在setArray之前的任何读取操作将在添加之前返回旧数据).此外, CopyOnWriteArrayList提供快照故障安全迭代器,并且不会在write/add上抛出ConcurrentModifficationException.
但是当我检查了CopyOnWriteArrayList.class的add方法时,我们正在获取完整集合对象的锁定.那么CopyOnWriteArrayList如何比synchronizedList更好.我在CopyOnWriteArrayList的add方法中看到的唯一区别是我们每次调用add方法时都会创建该数组的副本.
归档时间: |
|
查看次数: |
12147 次 |
最近记录: |