基本介绍
java并发包中的并发 List 只有 CopyOnWriteArrayList。 CopyOnWriteArrayList是一个线程 安全的ArrayList,对其进行的修改操作都是在底层的一个复制的数组(快照)上进行的, 也就是使用了写时复制策略。
CopyOnWriteArrayList 类里面有一个array数组变量用来存放具体元素, 一个ReentrantLock 独占锁变量用来保证同时只有一个线程对array进行修改。
CopyOnWriteArrayList 总体具有以下特点:
- 它是线程安全的。
- 因为通常需要复制整个基础数组,所以可变操作(add()、set() 和 remove() 等等)的开销较大。
- 迭代器支持hasNext(), next()等不可变操作,但不支持可变 remove()等操作。
- 使用迭代器进行遍历的速度很快,并且不会与其他线程发生冲突。在构造迭代器时,迭代器依赖于不变的数组快照,具有弱一致性。
- 适合于具有以下特征的应用程序:List 大小通常保持很小,只读操作远多于可变操作,需要在遍历期间防止线程间的冲突。
迭代器的弱一致性
所谓弱一致性是指list返回迭代器后,其他线程对 list 的增删改对迭代器是不可见。
下面通过一个例子来演示多线程下法代器的弱一致性的效果。
public class CopyOnWriteListTest { private static volatile CopyOnWriteArrayList list = new CopyOnWriteArrayList(); public static void main(String[] args) throws InterruptedException{ list.add("1"); list.add("2"); list.add("3"); list.add("4"); Thread threadChild = new Thread(new Runnable(){ @Override public void run() { list.set(1, "99"); list.add("5"); list.add("6"); } }); //在子线程启动前获取迭代器 Iterator iter = list.iterator(); //启动子线程 threadChild.start(); //等待子线程执行完毕 threadChild.join(); while(iter.hasNext()){ System.out.println(iter.next()); } }}
运行结果如下图
在如上代码中,main 函数首先初始化了list, 然后在启动子线程前获取到了 list 迭代器iter。 子线程 threadChild启动后首先修改了 list的第一个元素的值, 然后又添加了两个元素。
主线程在子线程执行完毕后使用获取的迭代器iter遍历数组元素,从输出结果我们知道,在子线程里面进行的操作一个都没有生效,这就是选代器弱一致性的体现。