集合线程安全 CopyOnWrite 是什么?

ArrayList

什么是ArrayList就不赘述了,主要是在多线程的情况下,线程是不安全的,原因是一条线程在对集合进行遍历,然而另一条却对数组进行修改,那么这样就很容易触发ConcurrentModificationException异常。

那么解决线程不安全的方法有:

  • 用过时的方法Vactor,同ArrayList一样底层是一个数组,其中大部分方法都被synchronized关键字所修饰,扩容方法与ArrayList不同,是2倍的扩容。

  • 用Collections工具类

    List<String> list = Collections.synchronizedList(new ArrayList<>());
    
  • CopyOnWriteArrayList

    List<String> list = CopyOnWriteArrayList<>();
    

    效率高,没有同步锁。


CopyOnWrite

是并发的一种新思路,实现读写分离。在并发环境下保证了线程安全,如果线程进行写入操作,那么它会复制一个原本的集合,在新的集合内作添加或删除元素操作。待修改完成之后,再将原集合的引用指向新的集合。

  • 好处是,可以高并发地对COW进行读和遍历操作,而不需要加锁,因为原集合不会添加任何元素。

  • 坏处是,在某些时刻,内存占用可能会过大从而频繁触发GC,减低服务器性能。

  • 使用COW需注意:

    • 使用批量添加或删除方法,如addAll 或removeAll 操作,在高并发请求下,可以攒一下要添加或删除的元素,避免增加一个元素复制整个集合。
    • 原因:假如几何数据是200MB,再写入10MB,那么某个时间段内占用的就达到(200MB * 2) + 10MB = 410MB,会频繁触发GC。

举例说明,CopyOnWriteArrayList 到底能有慢?(根据各自电脑不同,有所差异)
ArrayList:

List list = new ArrayList();
long a = System.currentTimeMillis();
for (int i = 0; i < 20 * 10000; i++) {
    list.add(i);
}
long b = System.currentTimeMillis();
long c = b - a;
System.out.println(c);      // 18

CopyOnWriteArrayList:

List cow = new CopyOnWriteArrayList();
long a = System.currentTimeMillis();
for (int i = 0; i < 20 * 10000; i++) {
     cow.add(i);
 }
long b = System.currentTimeMillis();
long c = b - a;
System.out.println(c);		// 28016

在这里插入图片描述
愿世上没有Bug

猜你喜欢

转载自blog.csdn.net/PINKMIAO/article/details/108479891