什么是CopyOnWrite

前段时间写过一篇关于concurrentHashMap的文章ConcurrentHashMap实现原理,其中讲到了实现ConcurrentHashMap的原理,这篇文章就讲一下CopyOnWrite的实现原理。Java中提供了两个CopyOnWrite容器,分别是CopyOnWriteArrayList和CopyOnWriteArraySet。如果想要高效的使用这两个容器,我觉的首先要弄懂CopyOnWrite的原理。那么下面就先来谈谈什么是CopyOnWrite吧。

什么是CopyOnWrite

CopyOnWrite即写时复制,该机制在于控制对数据的操作,什么时候需要对数据的操作进行控制呢,当然是在并发的时候,如果程序只是单线程的,所有对数据的操作都是顺序执行,那么数据的一致性就自然能得到保证。但是当有多个线程并发对数据进行操作的时候,情况就没那么简单了,一个线程修改了数据,另一个线程在数据被修改的过程中又读取了数据并对它进行修改,然后把修改的结果写回主内存,于是就会丢失一个线程对数据所做的修改。这种情况可以通过线程同步来解决,但是同步代码会大大降低并发效率。那么,有没有什么更好的方法来解决这个问题呢,当然,这个方法就是CopyOnWrite!首先我们可以来分析一下对数据的并发访问有哪些情况,如果我们仔细一想就会发现,并发访问数据的情况也无非下面这几种:读读、读写、写读、写写。针对这几种情况,可以分别对并发效率进行优化。

  • 读读这种情况是不需要加锁的,多个线程可以同时读取数据。
  • 读写这种情况便要考虑到对数据一致性的要求高低,我们可以将读锁写锁分离,读取数据时不加锁,修改数据时加写锁,这样相当于只同步了执行写操作的线程,但是由于写线程在修改数据时,读线程仍然可以读取数据,所以这样会造成一定程度的数据不一致。如果对数据一致性要求比较高,可以在修改数据时同时加写锁和读锁,这样写线程在修改数据时,读线程也必须等待。
  • 写读这种情况,同样可以使用读写锁分离的方式,但是更好的方法就是使用CopyOnWrite,对读线程不加锁,写线程修改数据时,先把原数据复制一份进行修改,读线程仍然读到的是旧数据,修改完之后再将原数据的引用指向新的数据,注意这时候写线程仍然是需要加锁的,否则多个线程将会复制出多个副本。
  • 写写这种情况就只好进行同步了,但是仍然可以通过降低锁的粒度来进行优化。

其实上面所讲到的这些,不仅仅是在Java多线程并发处理领域有应用,在数据库并发事务处理方面也有广泛应用,这篇文章数据库事务与其隔离级别中有相关概念的介绍。

CopyOnWrite适用场景

CopyOnWrite机制适用于读多写少的场景,比如搜索引擎对某些关键词的过滤使用的黑名单,黑名单很久才会更新一次,但是几乎每时每刻都在被读取。这种机制不适用于对数据实时性要求较高的场景中,因为一个线程修改了数据,其他线程并不一定能够马上读取到新的数据。

时间: 2024-10-07 10:47:57

什么是CopyOnWrite的相关文章

Copy-On-Write容器

Copy-On-write简称COW,是一种用于程序设计中的优化策略. JDK里的COW容器有两种:CopyOnWriteArrayList和CopyOnWriteArraySet,COW容器非常有用,可以在非常多的并发场景中使用到. CopyOnWrite容器即写时复制的容器.通俗的理解是当我们往一个容器添加元素的时候,不直接往当前容器添加,而是先将当前容器进行Copy,复制出一个新的容器. 这样做的好处是我们可以对CopyOnWrite容器进行并发的读,而不需要加锁,因为当前容器不会添加任何

Java并发(6):concurrent包中的Copy-On-Write容器

Copy-On-Write简称COW,是一种用于程序设计中的优化策略.其基本思路是,从一开始大家都在共享同一个内容,当某个人想要修改这个内容的时候,才会真正把内容Copy出去形成一个新的内容然后再改,这是一种延时懒惰策略.从JDK1.5开始Java并发包里提供了两个使用CopyOnWrite机制实现的并发容器,它们是CopyOnWriteArrayList和CopyOnWriteArraySet.CopyOnWrite容器非常有用,可以在非常多的并发场景中使用到. 一. CopyOnWrite容

Java再学习——CopyOnWrite容器

一,定义 CopyOnWrite容器即写时复制的容器.通俗的理解是当我们往一个容器添加元素的时候,不直接往当前容器添加,而是先将当前容器进行Copy,复制出一个新的容器,然后新的容器里添加元素,添加完元素之后,再将原容器的引用指向新的容器.这样做的好处是我们可以对CopyOnWrite容器进行并发的读,而不需要加锁,因为当前容器不会添加任何元素.所以CopyOnWrite容器也是一种读写分离的思想,读和写不同的容器.目前Java并发包里提供了两个使用CopyOnWrite机制实现的并发容器,它们

Linux写时拷贝技术(copy-on-write)

1.传统的fork()函数创建一个子进程,子进程和父进程共享正文段,复制数据段,堆,栈到子进程示意图如下: 2.Linux的fork()函数-写时复制(copy-on-write)创建一个子进程,内核只为子进程创建虚拟空间,不分配物理内存,和父进程共享物理空间,当父进程中有更改相应段的行为发生时,才为子进程分配物理空间.示意图如下: 3.vfork()函数创建一个子进程,共享父进程的一切.示意图如下: 4.传统fork与copy-on-write区别 传统的fork函数直接把所有资源复制给新的进

Java中的CopyOnWrite

CopyOnWrite简称COW,是一种程序设计的一种优化的策略方法,他开始的思想就是大家一起共享一件东西或商品,当一个人想要改这个事物原有的状态时,会重新复制一份出去,然后再新的事物上面改他所需要的东西,而不会影响以前的事物,然后再将原有的事物的引用到新的事物上来,思想类似于延时懒惰策略的方法,在jdk1.5之后,java出来了CopyOnWriteList和CopyOnWriteSet两种. CopyOnWrite也是一个容器,当大家都对这个容器做查看的时候,一个人想要添加水到容器的时候,这

锁 和 CopyOnWrite的实现

1.普通锁 只有lock功能, Java实现:ReentrantLock lock = new ReentrantLock(); lock和unlock: lock.lock(); lock.unlock(); 2.读写锁 读写锁:分为读锁和写锁,多个读锁不互斥,读锁与写锁互斥. 总之,读的时候上读锁,写的时候上写锁! Java里面的实现:ReentrantReadWriteLock ReadWriteLock mylock = new ReentrantReadWriteLock(false)

并发-Java中的Copy-On-Write容器

Copy-On-Write简称COW,是一种用于程序设计中的优化策略.其基本思路是,从一开始大家都在共享同一个内容,当某个人想要修改这个内容的时候,才会真正把内容Copy出去形成一个新的内容然后再改,这是一种延时懒惰策略.从JDK1.5开始Java并发包里提供了两个使用CopyOnWrite机制实现的并发容器,它们是CopyOnWriteArrayList和CopyOnWriteArraySet.CopyOnWrite容器非常有用,可以在非常多的并发场景中使用到. 什么是CopyOnWrite容

JAVA中写时复制(Copy-On-Write)Map实现

1,什么是写时复制(Copy-On-Write)容器? 写时复制是指:在并发访问的情景下,当需要修改JAVA中Containers的元素时,不直接修改该容器,而是先复制一份副本,在副本上进行修改.修改完成之后,将指向原来容器的引用指向新的容器(副本容器). 2,写时复制带来的影响 ①由于不会修改原始容器,只修改副本容器.因此,可以对原始容器进行并发地读.其次,实现了读操作与写操作的分离,读操作发生在原始容器上,写操作发生在副本容器上. ②数据一致性问题:读操作的线程可能不会立即读取到新修改的数据

Linux写时拷贝技术(copy-on-write)

COW技术初窥: 在Linux程序中,fork()会产生一个和父进程完全相同的子进程,但子进程在此后多会exec系统调用,出于效率考虑,linux中引入了“写时复制“技术,也就是只有进程空间的各段的内容要发生变化时,才会将父进程的内容复制一份给子进程. 那么子进程的物理空间没有代码,怎么去取指令执行exec系统调用呢? 在fork之后exec之前两个进程用的是相同的物理空间(内存区),子进程的代码段.数据段.堆栈都是指向父进程的物理空间,也就是说,两者的虚拟空间不同,但其对应的物理空间是同一个.

ConcurrentMap与CopyOnWrite容器

ConcurrentMap接口下有两个重要的实现: ConcurrentHashMap ConcurrentSkipListMap(支持并发排序功能,弥补ConcurrentHashMap) ConcurrentHashMap内部使用段(Segment)来表示这些不同的部分,每个段其实就是一个小的HashTable,它们有自己的锁.只要多个修改操作发生在不同的段上,他们就可以并发进行.把一个整体分成了16个小段(Segment).也就是最高支持16个线程的并发修改操作.这也是在多线程场景时减小锁