CopyOnWriteArrayList实现原理-写时复制

CopyOnWriteArrayList 写时复制器

CopyOnWriteArrayList是Java并发包中提供的一个并发容器,它是个线程安全且读操作无锁的ArrayList,写操作则通过创建底层数组的新副本来实现,是一种读写分离的并发策略,我们也可以称这种容器为"写时复制器",Java并发包中类似的容器还有CopyOnWriteSet。

CopyOnWriteArrayList实现原理-写时复制

实现原理

我们都知道,集合框架中的ArrayList是非线程安全的,Vector虽是线程安全的,但由于简单粗暴的锁同步机制,性能较差。而CopyOnWriteArrayList则提供了另一种不同的并发处理策略(当然是针对特定的并发场景)。

很多时候,我们的系统应对的都是读多写少的并发场景。CopyOnWriteArrayList容器允许并发读,读操作是无锁的,性能较高。至于写操作,比如向容器中添加一个元素,则首先将当前容器复制一份,然后在新副本上执行写操作,结束之后再将原容器的引用指向新容器。

CopyOnWriteArrayList实现原理-写时复制

优点:

读操作性能很高,因为无需任何同步措施,比较适用于读多写少的并发场景

Java的list在遍历时,若中途有别的线程对list容器进行修改,则会抛出ConcurrentModificationException异常。而CopyOnWriteArrayList由于其"读写分离"的思想,遍历和修改操作分别作用在不同的list容器,所以在使用迭代器进行遍历时候,也就不会抛出ConcurrentModificationException异常了。

缺点:

缺点也很明显:

一是内存占用问题,毕竟每次执行写操作都要将原容器拷贝一份,数据量大时,对内存压力较大,可能会引起频繁GC;

二是无法保证实时性,Vector对于读写操作均加锁同步,可以保证读和写的强一致性。而CopyOnWriteArrayList由于其实现策略的原因,写和读分别作用在新老不同容器上,在写操作执行过程中,读不会阻塞但读取到的却是老容器的数据。

如下这段代码:

在子线程中,不断向CopyOnWriteArrayList<String>中添加元素。

主线程则在遍历 list对象。因为子线程中list 中不断添加新元素,程序会一直运行。

package com.demo.concurrent;

import java.util.ArrayList;

import java.util.List;

import java.util.concurrent.CopyOnWriteArrayList;

/**

* Created by rickie on 2018/12/12.

*/

public class CopyOnWriteDemo {

public static void main(String[] args) throws InterruptedException {

//List<String> lst = new ArrayList<String>();

CopyOnWriteArrayList<String> lst = new CopyOnWriteArrayList<String>();

lst.add("a");

lst.add("b");

lst.add("c");

//final CopyOnWriteArrayList<String> cow = new CopyOnWriteArrayList<String>(lst);

//final ArrayList<String> cow = new ArrayList<>(lst);

Thread t = new Thread(new Runnable() {

int count = -1;

@Override

public void run() {

while (true){

lst.add(count++ + "");

System.out.println(count);

}

}

});

t.setDaemon(true);

t.start();

Thread.currentThread().sleep(300);

for(String s: lst){

System.out.println(lst.hashCode() + " -- " + s);

}

}

}

CopyOnWriteArrayList实现原理-写时复制

相关推荐