CopyOnWriteArrayList分析
程序员文章站
2022-07-14 16:10:11
...
引用源码的注释
This is ordinarily too costly, but may be more efficient than alternatives when traversal operations vastly outnumber mutations, and is useful when you cannot or don't want to synchronize traversals, yet need to preclude interference among concurrent threads.
CopyOnWriteArrayList的实现很简单,主要是理解为什么要用它。上面已经说了在遍历操作远多于添加和删除元素操作时可以使用CopyOnWriteArrayList。注意这里只涉及3种操作:遍历操作、添加元素和删除元素。这里甚至都没有处理并发修改元素值时可能遇到的问题,所以显然CopyOnWriteArrayList的是为了解决上面那三种并发时可能产生的问题,下面解释究竟解决了什么问题。
通常在遍历数组时有两种方式
- 通过Iterator遍历,foreach 循环遍历list时也是使用的Iterator。这种方式遍历时会产生ConcurrentModificationException异常。
- 通过索引遍历,foreach 循环遍历数组时使用索引遍历方法,这种方式遍历时会产生IndexOutOfBoundsException异常。
因此,如果想要使遍历和修改数组长度的的操作在并发时不产生异常,只能使用同步。一般情况下遍历操作、添加元素以及删除元素都需要加锁。但是在遍历操作远多于添加和删除元素操作时,对读操作加锁会导致很大的性能影响,因此采用CopyOnWriteArrayList可以保证读操作不加锁。
但是CopyOnWriteArrayList也不是免费的解决方案,它有两个缺点:
- 遍历操作会读到失效数据
- 复制会导致大量的内存消耗
public class COWListTest {
public static void main(String args[]) throws InterruptedException {
CopyOnWriteArrayList<Integer> COWList =
IntStream.iterate(0,a->a+1)
.limit(10)
.boxed()
.collect(toCollection(CopyOnWriteArrayList::new));
Thread thread1 = new Thread(() -> COWList.remove(5));
Thread thread2 = new Thread(() -> {
// 1、通过迭代器遍历
for(Integer val : COWList)
System.out.println(val);
///2、通过索引遍历
for (int i = 0; i < 10; i++)
System.out.println(COWList.get(i));
});
thread2.start();
thread1.start();
thread1.join();
thread2.join();
}
}
推荐阅读
-
oracle修改SGA后无法启动问题分析及解决方法
-
基于python历史天气采集的分析
-
PHP超级全局变量【$GLOBALS,$_SERVER,$_REQUEST等】用法实例分析
-
深入探讨:oracle中row_number() over()分析函数用法
-
对比分析php中Cookie与Session的异同
-
laravel5.5框架的上传图片功能实例分析【仅传到服务器端】
-
Laravel5.1框架自带权限控制系统 ACL用法分析
-
MySQL中使用replace、regexp进行正则表达式替换的用法分析
-
mysql基于正则实现模糊替换字符串的方法分析
-
MySQL慢查询之pt-query-digest分析慢查询日志