首页技术文章正文

Java并发-CopyOnWriteArrayList【黑马java培训】

更新时间:2021年03月18日 08时58分24秒 来源:黑马程序员论坛

黑马中级程序员课程

Java并发-CopyOnWriteArrayList



前言
今天我们一起学习下java.util.concurrent并发包里的CopyOnWriteArrayList工具类。当有多个线程可能同时遍历、修改某个公共数组时候,如果不希望因使用synchronize关键字锁住整个数组而影响性能,可以考虑使用CopyOnWriteArrayList。
CopyOnWriteArrayList API
CopyOnWriteArrayList的定义如下:
public class CopyOnWriteArrayList
extends Object
implements List, RandomAccess, Cloneable, Serializable
它也属于Java集合框架的一部分,是ArrayList的线程安全的变体,跟ArrayList的不同在于:CopyOnWriteArrayList针对数组的修改操作(add、set等)是基于内部拷贝的一份数据而进行的。换句话说,即使在一个线程进行遍历操作时有其他线程可能进行插入或删除操作,我们也可以“线程安全”得遍历CopyOnWriteArrayList。
例子1:插入(删除)数据的同时进行遍历
CopyOnWriteArrayList的实现原理是,在一个线程开始遍历(创建Iterator对象)时,内部会创建一个“快照”数组,遍历基于这个快照Iterator进行,在遍历过程中这个快照数组不会改变,也就不会抛出ConcurrentModificationException。如果在遍历的过程中有其他线程尝试改变数组的内容,就会拷贝一份新的数据进行变更,而后面再来访问这个数组的线程,看到的就是变更过的数组。
创建一个CopyOnWriteArrayList数组numbers;
CopyOnWriteArrayList numbers = new CopyOnWriteArrayList<>(new Integer[]{1, 3, 5, 78});
创建一个遍历器iterator;
Iterator iterator = numbers.iterator();
给numbers中增加(或删除、修改)一个元素;
numbers.add(100);
利用iterator遍历数组的元素,发现遍历的结果是Iterator对象创建之前的;
List result = new LinkedList<>();
iterator.forEachRemaining(result::add);
assertThat(result).containsOnly(1, 3, 5, 78);
完整的例子如下:
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 {
[Java] 纯文本查看 复制代码
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 {
[Java] 纯文本查看 复制代码
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,新老版本分离,保证读的高性能,适用于以读为主的情况。


推荐了解热门学科

java培训 Python人工智能 Web前端培训 PHP培训
区块链培训 影视制作培训 C++培训 产品经理培训
UI设计培训 新媒体培训 产品经理培训 Linux运维
大数据培训 智能机器人软件开发




传智播客是一家致力于培养高素质软件开发人才的科技公司“黑马程序员”是传智播客旗下高端IT教育品牌。自“黑马程序员”成立以来,教学研发团队一直致力于打造精品课程资源,不断在产、学、研3个层面创新自己的执教理念与教学方针,并集中“黑马程序员”的优势力量,针对性地出版了计算机系列教材50多册,制作教学视频数+套,发表各类技术文章数百篇。

传智播客从未停止思考

传智播客副总裁毕向东在2019IT培训行业变革大会提到,“传智播客意识到企业的用人需求已经从初级程序员升级到中高级程序员,具备多领域、多行业项目经验的人才成为企业用人的首选。”

中级程序员和初级程序员的差别在哪里?
项目经验。毕向东表示,“中级程序员和初级程序员最大的差别在于中级程序员比初级程序员多了三四年的工作经验,从而多出了更多的项目经验。“为此,传智播客研究院引进曾在知名IT企业如阿里、IBM就职的高级技术专家,集中研发面向中高级程序员的课程,用以满足企业用人需求,尽快补全IT行业所需的人才缺口。

何为中高级程序员课程?

传智播客进行了定义。中高级程序员课程,是在当前主流的初级程序员课程的基础上,增加多领域多行业的含金量项目,从技术的广度和深度上进行拓展“我们希望用5年的时间,打造上百个高含金量的项目,覆盖主流的32个行业。”传智播客课程研发总监于洋表示。




黑马程序员热门视频教程【点击播放】

Python入门教程完整版(懂中文就能学会) 零起点打开Java世界的大门
C++| 匠心之作 从0到1入门学编程 PHP|零基础入门开发者编程核心技术
Web前端入门教程_Web前端html+css+JavaScript 软件测试入门到精通


分享到:
在线咨询 我要报名
和我们在线交谈!