CopyOnWriteArrayList

CopyOnWriteArrayList是Arraylist 的一个线程安全的变体,其中所有可变操作(add、set等等)都是通过对底层数组进行一次新的复制来实现的。

     这一般需要很大的开销,但是当遍历操作的数量大大超过可变操作的数量时,这种方法可能比其他替代方法 有效。在不能或不想进行同步遍历,但又需要从并发线程中排除冲突时,它也很有用。“快照”风格的迭代器方法在创建迭代器时使用了对数组状态的引用。此数组在迭代器的生存期内不会更改,因此不可能发生冲突,并且迭代器保证不会抛出ConcurrentModificationException。创建迭代器以后,迭代器就不会反映列表的添加、移除或者更改。在迭代器上进行的元素更改操作(remove、set和add)不受支持。这些方法将抛出UnsupportedOperationException。允许使用所有元素,包括null。

CopyOnWriteArrayList适合使用在读操作远远大于写操作的场景里,比如缓存。发生修改时候做copy,新老版本分离,保证读的高性能,适用于以读为主的情况.

对读操作不加锁,对写操作,先复制一份新的集合,在新的集合上面修改,然后将新集合赋值给旧的引用,并通过volatile 保证其可见性,当然写操作的锁是必不可少的了。


如果避免这些错误发生呢?本文列出了几种常见的使用场景:
【场景一】对于ArrayList,使用直接方式,一边遍历,一边删除,会报错。
for(String item : list)
{
list.remove(item);
}
解决办法一:使用迭代器,一边遍历,一边删除,不会报错。
Iterator it = list.iterator();
while(it.hasNext())
{
String ele = it.next();
it.remove();
}
解决办法二:使用CopyOnWriteArrayList,一边遍历,一会删除,不会报错。
for(String item : list)
{
list.remove(item);
}
【场景二】对于ArrayList,使用迭代器,一边遍历,一边add,会报错。
Iterator it = list.iterator();
while(it.hasNext())
{
String str = it.next();
String tem = str + “…”;
list.add(tem);
}
解决办法一:改用CopyOnWriteArrayList,一边遍历,一边add,不会报错。
for(String item : list)
{
String tem = item + “…”;
list.add(tem);
}

解决办法二:改用CopyOnWriteArrayList,一边遍历,一边add,不会报错。
Iterator it = list.iterator();
while(it.hasNext())
{
String str = it.next();
String tem = str + “…”;
list.add(tem);
}
【场景三】对于CopyOnWriteArrayList,迭代器,不能remove。
Iterator it = list.iterator();
while(it.hasNext())
{
String str = it.next();
String tem = str + “…”;
it.remove();
}
解决办法一:使用直接方式,一边遍历,一边add/remove()
for(String item : list)
{
String tem = item + “…”;
list.remove(item);
list.add(tem);
}

你可能感兴趣的:(CopyOnWriteArrayList)