Copy-On-Write容器
Copy-On-Write简称COW,是一种用于程序设计中的优化策略。其基本思路是,从一开始大家都在共享同一个内容,当某个人想要修改这个内容的时候,才会真正把内容Copy出去形成一个新的内容然后再改,这是一种延时懒惰策略。从JDK1.5开始Java并发包里提供了两个使用CopyOnWrite机制实现的并发容器,它们是CopyOnWriteArrayList和CopyOnWriteArraySet。CopyOnWrite容器非常有用,可以在非常多的并发场景中使用到。
CopyOnWrite容器即写时复制的容器。通俗的理解是当我们往一个容器添加元素的时候,不直接往当前容器添加,而是先将当前容器进行Copy,复制出一个新的容器,然后新的容器里添加元素,添加完元素之后,再将原容器的引用指向新的容器。这样做的好处是我们可以对CopyOnWrite容器进行并发的读,而不需要加锁,因为当前容器不会添加任何元素。所以CopyOnWrite容器也是一种读写分离的思想,读和写不同的容器。
CopyOnWriteArrayList的实现原理
以下代码是向ArrayList里添加元素,可以发现在添加的时候是需要加锁的,否则多线程写的时候会Copy出N个副本出来。
public boolean add(T e) {
final ReentrantLock lock = this.lock;
lock.lock();
try {
Object[] elements = getArray();
int len = elements.length;
// 复制出新数组
Object[] newElements = Arrays.copyOf(elements, len + 1);
// 把新元素添加到新数组里
newElements[len] = e;
// 把原数组引用指向新数组
setArray(newElements);
return true;
} finally {
lock.unlock();
}
读的时候不需要加锁,如果读的时候有多个线程正在向ArrayList添加数据,读还是会读到旧的数据,因为写的时候不会锁住旧的ArrayList。
public E get(int index) {
return get(getArray(), index);
}
CopyOnWrite的应用场景
CopyOnWrite并发容器用于读多写少的并发场景。比如白名单,黑名单,商品类目的访问和更新场景,假如我们有一个搜索网站,用户在这个网站的搜索框中,输入关键字搜索内容,但是某些关键字不允许被搜索。这些不能被搜索的关键字会被放在一个黑名单当中,黑名单每天晚上更新一次。当用户搜索时,会检查当前关键字在不在黑名单当中,如果在,则提示不能搜索。
CopyOnWrite的缺点
CopyOnWrite容器有很多优点,但是同时也存在两个问题,即内存占用问题和数据一致性问题。
内存占用问题。因为CopyOnWrite的写时复制机制,所以在进行写操作的时候,内存里会同时驻扎两个对象的内存,旧的对象和新写入的对象。如果这些对象占用的内存比较大,比如说200M左右,那么再写入100M数据进去,内存就会占用300M,那么这个时候很有可能造成频繁的Yong GC和Full GC。针对内存占用问题,可以通过压缩容器中的元素的方法来减少大对象的内存消耗,比如,如果元素全是10进制的数字,可以考虑把它压缩成36进制或64进制。或者不使用CopyOnWrite容器,而使用其他的并发容器,如ConcurrentHashMap。
数据一致性问题。CopyOnWrite容器只能保证数据的最终一致性,不能保证数据的实时一致性。所以如果你希望写入的的数据,马上能读到,请不要使用CopyOnWrite容器。
Copy-On-Write容器的更多相关文章
- C++ - 使用copy函数打印容器(container)元素
使用copy函数打印容器(container)元素 本文地址: http://blog.csdn.net/caroline_wendy C++能够使用copy函数输出容器(container)中的元素 ...
- 使用copy函数输出容器中的内容
container<type> c; 输出语句为:copy(c.begin(), c.end(), ostream_iterator<type>(cout, " &q ...
- JAVA 多线程随笔 (三) 多线程用到的并发容器 (ConcurrentHashMap,CopyOnWriteArrayList, CopyOnWriteArraySet)
1.引言 在多线程的环境中,如果想要使用容器类,就需要注意所使用的容器类是否是线程安全的.在最早开始,人们一般都在使用同步容器(Vector,HashTable),其基本的原理,就是针对容器的每一个操 ...
- STL中copy算法
STL中通过使用copy函数以提供一种方便的方式来输出容器中的元素.函数copy作为泛型算法的一部分,任何容器类型都可以使用.由于我们需要频繁的初始容器的元素,因此在继续讨论容器之前,先学习一下cop ...
- NSCopy&NSMutableCopy
struct student { int a; float f; char c; long l; }; struct person { int a; float f; char c; long l; ...
- java Iterator Fail-fast机制
Fail-fast:在迭代的过程中发现数据被改变时立即抛出异常,而不是等遍历完了再抛出异常:可以理解为快速感知. 在并发的时候,当线程A正遍历一个Collection或Map,这时另外一个线程B修改C ...
- Windows Azure 基本操作手册
http://www.cnblogs.com/sennly/p/4139663.html 基本测试信息 登陆地址:https://manage.windowsazure.cn(Azure管理门户,适用 ...
- Docker系列(三)常用命令
命令说明 docker pull 格式: docke pull [OPTIONS] NAME[:TAG] 作用:下载名称为 name 的镜像 例子: sudo docker pull dl.docke ...
- JAVA提高二十:CopyOnWriteArrayList&CopyOnWriteArraySet&ConcurrentHashMap介绍
前面我们将java集合类的大部分类都进行了深入分析,但我们会发现一个共性问题就是并发的问题,那么如何解决呢?我们前面基本都是通过Collections的一个工具类来进行的解决,但实际大部分使用中人们普 ...
- 【Docker】Docker概述
[Docker] Docker可以说是近几年非常热门的技术之一了.不管是别人敦促我还是从自己的想法来说,都觉得Docker这玩意儿肯定是要好好学习一下的,无奈没啥时间专门播出来给Docker,一直以来 ...
随机推荐
- EBS提交请求出现REP-3000错误
在AIX上利用并发请求提交报表的時候,出现如下错误:REP-3000: Internal error starting Oracle Toolkit.这是因为Report Server需要X-Wind ...
- highcharts饼状图使用案例
在公司由于需要对订单数据进行分析,故使用到了highcharts工具 <block name="Js"> <script type="text/java ...
- Eclipse相关问题
如何修改Eclipse的 workspace目录 Eclipse是一款很强的Java IDE,我们在开始的时候,往往设定了默认的workspace,当用久在之后,我们可能要去更改一下workspace ...
- PYTHON 随机验证码生成
# 生成一个六位随机验证码 import random # random 生成随机数 temp = '' for i in range(6): num = random.randrange(0,6) ...
- PHPSTORM设置新建PHP文件头部注释
1.选择 File|setting 2.在Editor|File and Code Templates,见下图标记更改即可
- erlang 故障排查工具
系统级别perf top, dstat -tam, vtune 都能很好分析beam 瓶颈,本文主要erlang 级别排查: 1. 反编译 确认线上运行代码是否正确,reltools没掌握好,升级偶尔 ...
- 按钮button的css样式(扁平化底色)
.button { background-color: #ff0000; /* Green */ border: none; color: white; font-family:Arial; padd ...
- 浅析Java中的final关键字(转载)
自http://www.cnblogs.com/dolphin0520/p/3736238.html转载 一.final关键字的基本用法 在Java中,final关键字可以用来修饰类.方法和变量(包括 ...
- c/c++ 缓冲区的刷新
利用string 对象查看缓冲区的变化,因为每个string对象在输入时会以空格作为分界. #include<iostream> #include<string> using ...
- Cocos2dx
初玩Cocos2dx,多多包涵. 感觉版本之间的差异比较大,相对前面的版本来说,3.X更容易上手,更方便了. 一.安装python.我的python-2.7.3.配置环境变量 系统变量里:在Path里 ...