证明CopyOnWriteArrayList是线程安全的

先写一段代码证明CopyOnWriteArrayList确实是线程安全的。

ReadThread.java

import java.util.List;

public class ReadThread implements Runnable {
private List<Integer> list;

public ReadThread(List<Integer> list) {
this.list = list;
}

@Override
public void run() {
for (Integer ele : list) {
System.out.println("ReadThread:"+ele);
}
}
}

WriteThread.java

import java.util.List;

public class WriteThread implements Runnable {
private List<Integer> list;

public WriteThread(List<Integer> list) {
this.list = list;
}

@Override
public void run() {
this.list.add(9);
}
}
TestCopyOnWriteArrayList.java

import java.util.Arrays;
import java.util.List;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class TestCopyOnWriteArrayList {

private void test() {
//1、初始化CopyOnWriteArrayList
List<Integer> tempList = Arrays.asList(new Integer [] {1,2});
CopyOnWriteArrayList<Integer> copyList = new CopyOnWriteArrayList<>(tempList);

//2、模拟多线程对list进行读和写
ExecutorService executorService = Executors.newFixedThreadPool(10);
executorService.execute(new ReadThread(copyList));
executorService.execute(new WriteThread(copyList));
executorService.execute(new WriteThread(copyList));
executorService.execute(new WriteThread(copyList));
executorService.execute(new ReadThread(copyList));
executorService.execute(new WriteThread(copyList));
executorService.execute(new ReadThread(copyList));
executorService.execute(new WriteThread(copyList));

System.out.println("copyList size:"+copyList.size());
}

public static void main(String[] args) {
new TestCopyOnWriteArrayList().test();
}
}

运行上面的代码,没有报出

java.util.ConcurrentModificationException
1
说明了CopyOnWriteArrayList并发多线程的环境下,仍然能很好的工作。

CopyOnWriteArrayList如何做到线程安全的

CopyOnWriteArrayList使用了一种叫写时复制的方法,当有新元素添加到CopyOnWriteArrayList时,先从原有的数组中拷贝一份出来,然后在新的数组做写操作,写完之后,再将原来的数组引用指向到新数组。

当有新元素加入的时候,如下图,创建新数组,并往新数组中加入一个新元素,这个时候,array这个引用仍然是指向原数组的。

当元素在新数组添加成功后,将array这个引用指向新数组。

CopyOnWriteArrayList的整个add操作都是在锁的保护下进行的。
这样做是为了避免在多线程并发add的时候,复制出多个副本出来,把数据搞乱了,导致最终的数组数据不是我们期望的。

CopyOnWriteArrayList的add操作的源代码如下:

public boolean add(E e) {
//1、先加锁
final ReentrantLock lock = this.lock;
lock.lock();
try {
Object[] elements = getArray();
int len = elements.length;
//2、拷贝数组
Object[] newElements = Arrays.copyOf(elements, len + 1);
//3、将元素加入到新数组中
newElements[len] = e;
//4、将array引用指向到新数组
setArray(newElements);
return true;
} finally {
//5、解锁
lock.unlock();
}
}

由于所有的写操作都是在新数组进行的,这个时候如果有线程并发的写,则通过锁来控制,如果有线程并发的读,则分几种情况:
1、如果写操作未完成,那么直接读取原数组的数据;
2、如果写操作完成,但是引用还未指向新数组,那么也是读取原数组数据;
3、如果写操作完成,并且引用已经指向了新的数组,那么直接从新数组中读取数据。

可见,CopyOnWriteArrayList的读操作是可以不用加锁的。

CopyOnWriteArrayList的使用场景

通过上面的分析,CopyOnWriteArrayList 有几个缺点:
1、由于写操作的时候,需要拷贝数组,会消耗内存,如果原数组的内容比较多的情况下,可能导致young gc或者full gc

2、不能用于实时读的场景,像拷贝数组、新增元素都需要时间,所以调用一个set操作后,读取到数据可能还是旧的,虽然CopyOnWriteArrayList 能做到最终一致性,但是还是没法满足实时性要求;

CopyOnWriteArrayList 合适读多写少的场景,不过这类慎用
因为谁也没法保证CopyOnWriteArrayList 到底要放置多少数据,万一数据稍微有点多,每次add/set都要重新复制数组,这个代价实在太高昂了。在高性能的互联网应用中,这种操作分分钟引起故障。

CopyOnWriteArrayList透露的思想

如上面的分析CopyOnWriteArrayList表达的一些思想:
1、读写分离,读和写分开
2、最终一致性
3、使用另外开辟空间的思路,来解决并发冲突

参考的文章

JAVA中的COPYONWRITE容器
---------------------
作者:Sam哥哥
来源:CSDN
原文:https://blog.csdn.net/linsongbin1/article/details/54581787
版权声明:本文为博主原创文章,转载请附上博文链接!

https://coolshell.cn/articles/11175.html

线程安全的CopyOnWriteArrayList的更多相关文章

  1. 线程安全的CopyOnWriteArrayList介绍

    证明CopyOnWriteArrayList是线程安全的 先写一段代码证明CopyOnWriteArrayList确实是线程安全的. ReadThread.java import java.util. ...

  2. CopyOnWriteArrayList真的完全线程安全吗

    我之前书上看到的说法是:Vector是相对线程安全,CopyOnWriteArrayList是绝对线程安全 这种说法其实有些问题,CopyOnWriteArrayList在某些场景下还是会报错的 Co ...

  3. Java并发编程:并发容器之CopyOnWriteArrayList(转载)

    Java并发编程:并发容器之CopyOnWriteArrayList(转载) 原文链接: http://ifeve.com/java-copy-on-write/ Copy-On-Write简称COW ...

  4. Java并发编程:并发容器之CopyOnWriteArrayList

    转载: Java并发编程:并发容器之CopyOnWriteArrayList Copy-On-Write简称COW,是一种用于程序设计中的优化策略.其基本思路是,从一开始大家都在共享同一个内容,当某个 ...

  5. 并发容器之CopyOnWriteArrayList

    原文链接: http://ifeve.com/java-copy-on-write/ Copy-On-Write简称COW,是一种用于程序设计中的优化策略.其基本思路是,从一开始大家都在共享同一个内容 ...

  6. 【多线程】Java并发编程:并发容器之CopyOnWriteArrayList(转载)

    原文链接: http://ifeve.com/java-copy-on-write/ Copy-On-Write简称COW,是一种用于程序设计中的优化策略.其基本思路是,从一开始大家都在共享同一个内容 ...

  7. 并发容器之CopyOnWriteArrayList(转载)

    Copy-On-Write简称COW,是一种用于程序设计中的优化策略.其基本思路是,从一开始大家都在共享同一个内容,当某个人想要修改这个内容的时候,才会真正把内容Copy出去形成一个新的内容然后再改, ...

  8. (转)Java并发编程:并发容器之CopyOnWriteArrayList

    原文链接:http://ifeve.com/java-copy-on-write/ Copy-On-Write简称COW,是一种用于程序设计中的优化策略.其基本思路是,从一开始大家都在共享同一个内容, ...

  9. 并发容器之CopyOnWriteArrayList(转载)

    Copy-On-Write简称COW,是一种用于程序设计中的优化策略.其基本思路是,从一开始大家都在共享同一个内容,当某个人想要修改这 个内容的时候,才会真正把内容Copy出去形成一个新的内容然后再改 ...

随机推荐

  1. c#获取Amr文件的时长(毫秒)亲测有效

    /// <summary> /// c#获取Amr文件的时长(毫秒) /// </summary> /// <param name="fileName" ...

  2. [django]modelform实现的多文件上传

    实现效果 代码 models.py from django.db import models import uuid class UUIDTools(object): ""&quo ...

  3. 9个Linux系统常用监控命令

    我们的系统一旦上线跑起来我们自然希望它一直相安无事,不要宕机,不要无响应,不要慢腾腾的.但是这不是打开机器电源然后放任不管就可以得到的.所以我们要监视系统的运行状况,发现问题及时处理. 对于系统和网络 ...

  4. Centos7上安装Apache

    Apache HTTP服务器是世界上最流行的Web服务器. 它是一款免费的开源和跨平台的HTTP服务器,提供强大的功能,可以通过各种模块进行扩展. 以下说明介绍如何在CentOS 7机器上安装和管理A ...

  5. [LeetCode] 603. Consecutive Available Seats_Easy tag: SQL

    Several friends at a cinema ticket office would like to reserve consecutive available seats.Can you ...

  6. [LeetCode] 744. Find Smallest Letter Greater Than Target_Easy tag: **Binary Search

    Given a list of sorted characters letters containing only lowercase letters, and given a target lett ...

  7. How to compile and install Snort from source code on Ubuntu

    http://www.tuicool.com/articles/v6j2Ab Snort is by far the most popular open-source network intrusio ...

  8. vim自动安装插件Vundle

    https://github.com/VundleVim/Vundle.vim Set up Vundle: git clone https://github.com/VundleVim/Vundle ...

  9. nodejs连接数据库的增删改查

    连接数据库后需要用代码操作的是,传入mysql语句,和参数,然后就是回调了 新增 // 新增 app.post('/process_post', urlencodedParser, function ...

  10. HDU 2276 Kiki & Little Kiki 2(矩阵位运算)

    Kiki & Little Kiki 2 转载自:点这里 [题目链接]Kiki & Little Kiki 2 [题目类型]矩阵位运算 &题意: 一排灯,开关状态已知,每过一秒 ...