黑马程序员技术交流社区

标题: 【上海校区】Java并发-CopyOnWriteArrayList [打印本页]

作者: 不二晨    时间: 2018-12-10 10:02
标题: 【上海校区】Java并发-CopyOnWriteArrayList
CopyOnWriteArrayList API
CopyOnWriteArrayList的定义如下:
public class CopyOnWriteArrayList<E>extends Objectimplements List<E>, RandomAccess, Cloneable, Serializable
它也属于Java集合框架的一部分,是ArrayList的线程安全的变体,跟ArrayList的不同在于:CopyOnWriteArrayList针对数组的修改操作(add、set等)是基于内部拷贝的一份数据而进行的。换句话说,即使在一个线程进行遍历操作时有其他线程可能进行插入或删除操作,我们也可以“线程安全”得遍历CopyOnWriteArrayList。
例子1:插入(删除)数据的同时进行遍历
CopyOnWriteArrayList的实现原理是,在一个线程开始遍历(创建Iterator对象)时,内部会创建一个“快照”数组,遍历基于这个快照Iterator进行,在遍历过程中这个快照数组不会改变,也就不会抛出ConcurrentModificationException。如果在遍历的过程中有其他线程尝试改变数组的内容,就会拷贝一份新的数据进行变更,而后面再来访问这个数组的线程,看到的就是变更过的数组。
完整的例子如下:
package org.java.learn.concurrent.copyonwritearraylist;import java.util.Iterator;import java.util.LinkedList;import java.util.List;import java.util.concurrent.CopyOnWriteArrayList;import static org.assertj.core.api.Assertions.*;/** * 作用: * User: duqi * Date: 2017/11/9 * Time: 11:20 */public class CopyOnWriteArrayListExample {    public static void main(String[] args) {        CopyOnWriteArrayList<Integer> numbers = new CopyOnWriteArrayList<>(new Integer[]{1, 3, 5, 78});        Iterator<Integer> iterator = numbers.iterator();        numbers.add(100);        List<Integer> result = new LinkedList<>();        iterator.forEachRemaining(result::add);        assertThat(result).containsOnly(1, 3, 5, 78);        Iterator<Integer> iterator2 = numbers.iterator();        numbers.remove(3);        List<Integer> result2 = new LinkedList<>();        iterator2.forEachRemaining(result2::add);        assertThat(result2).containsOnly(1, 3, 5, 78, 100);    }}例子2:不支持一边遍历一边删除
由于CopyOnWriteArrayList的实现机制——>修改操作和读操作拿到的Iterator对象指向的不是一个数组,因此不支持基于Iterator对象的方法结果的删除:public void remove();,例子代码如下:
package org.java.learn.concurrent.copyonwritearraylist;import java.util.Iterator;import java.util.concurrent.CopyOnWriteArrayList;/** * 作用: User: duqi Date: 2017/11/9 Time: 13:40 */public class CopyOnWriteArrayListExample2 {    public static void main(String[] args) {        try {            testExceptionThrow();        } catch (Exception e) {            e.printStackTrace();        }    }    private static void testExceptionThrow() {        CopyOnWriteArrayList<Integer> numbers = new CopyOnWriteArrayList<>(new Integer[]{1, 3, 5, 78});        Iterator<Integer> integerIterator = numbers.iterator();        while (integerIterator.hasNext()) {            integerIterator.remove();        }    }}结论
CopyOnWriteArrayList适合使用在读操作远远大于写操作的场景里,比如缓存。发生修改时候做copy,新老版本分离,保证读的高性能,适用于以读为主的情况。

【转载】仅作分享,侵删
链接:https://juejin.im/entry/5a03f4a2518825592c078cc9


作者: 不二晨    时间: 2018-12-11 15:05

作者: 小影姐姐    时间: 2018-12-13 14:52





欢迎光临 黑马程序员技术交流社区 (http://bbs.itheima.com/) 黑马程序员IT技术论坛 X3.2