前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >简单聊聊copy on write(写时复制)技术

简单聊聊copy on write(写时复制)技术

原创
作者头像
一个风轻云淡
修改2023-11-29 08:04:44
1.4K0
修改2023-11-29 08:04:44
举报
文章被收录于专栏:java学习java


基本介绍

概述

写时复制(英语:Copy-on-write,简称COW)是一种计算机领域的优化策略。其核心思想是,如果有多个调用者(callers)同时请求相同资源(如内存或磁盘上的数据存储),他们会共同获取相同的指针指向相同的资源,直到某个调用者试图修改资源的内容时,系统才会真正复制一份专用副本(private copy)给该调用者,而其他调用者所见到的最初的资源仍然保持不变

这过程对其他的调用者都是 [透明]的。此作法主要的优点是如果调用者没有修改该资源,就不会有副本(private copy) 被创建,因此多个调用者只是读取操作时可以共享同一份资源。

当需要修改某个共享数据时,先将原始数据复制一份,并在副本上进行修改,修改完成后再将副本的引用赋值给原始数据的引用 ,读写分离,空间换时间,避免为保证并发安全导致的激烈的锁竞争。

关键点

  • Copy-on-write适用于读多写少的情况,最大程度的提高读的效率;
  • Copy-on-write是最终一致性,在写的过程中,原有的读的数据是不会发生更新的,只有新的读才能读到最新数据;
  • 在java中,为了能使其他线程能够及时读到新的数据,需要使用volatile变量;
  • 写的时候不能并发写,需要对写操作进行加锁;

应用实现

数据库中的MVCC

多版本并发控制(MVCC) 在一定程度上实现了读写并发,它只在 可重复读(REPEATABLE READ) 和 提交读(READ COMMITTED) 两个隔离级别下工作。其他两个隔离级别都和 MVCC 不兼容,因为 未提交读(READ UNCOMMITTED),总是读取最新的数据行,而不是符合当前事务版本的数据行。而 可串行化(SERIALIZABLE) 则会对所有读取的行都加锁。

MVCC除了支持读和读并行,还支持读和写并行、写和读并行,但为了保持数据一致性,写和写是无法并行的。

行锁,并发,事务回滚等多种特性都和 MVCC 相关。MVCC 实现的核心思路就是 Copy On Write

在一个事务写的时候会copy一个记录的副本,其他事务的读操作会读取这个记录的副本,因此不影响其他事务对此记录的写入,实现写和读并行。

Java中的CopyOnWriteArrayList

CopyOnWriteArrayList 是jdk1.5以后并发包中提供的一种并发容器,写操作通过创建底层数组的新副本来实现,是一种读写分离的并发策略,我们也成为“写时复制容器”,类似的容器还有 CopyOnWriteArraySet。

代码语言:javascript
复制
public boolean add(E e) {
   //加锁,对写操作保证线程安全
   final ReentrantLock lock = this.lock;
   lock.lock();
   try {
       Object[] elements = getArray();
       int len = elements.length;
       //拷贝原容器,长度为原容器+1
       Object[] newElements = Arrays.copyOf(elements, len + 1);
       //在新副本执行添加操作
       newElements[len] = e;
       //底层数组指向新的数组
       setArray(newElements);
       return true;
   } finally {
       lock.unlock();
   }
}

CopyOnWriteArrayList底层实现添加的原理是先copy出一个容器(可以简称副本),再往新的容器里添加这个新的数据,最后把新的容器的引用地址赋值给了之前那个旧的的容器地址,但是在添加这个数据的期间,其他线程如果要去读取数据,仍然是读取到旧的容器里的数据。

读操作性能很高,因为无需任何同步措施,比较适用于读多写少的并发场景。Java 的 list 在遍历时,若中途有其他线程对容器进行修改,则会抛出ConcurrentModificationException 异常。而CopyOnWriteArrayList由于其“读写分离”的思想,遍历和修改操作分别作用在不同的 list容器,所以迭代的时候不会抛出 ConcurrentModificationExecption 异常了。

其存在数据一致性问题:CopyOnWrite容器只能保证数据的最终一致性,不能保证数据的实时一致性。如果希望写入的的数据,马上能读到,不要使用CopyOnWrite容器

Nacos避免并发读写冲突问题

Nacos在更新实例列表时,会采用CopyOnWrite技术,首先将旧的实例列表拷贝一份,然后更新拷贝的实例列表,再用更新后的实例列表来覆盖旧的实例列表。

这样在更新的过程中,就不会对读实例列表的请求产生影响,也不会出现脏读问题了。

​我正在参与2023腾讯技术创作特训营第三期有奖征文,组队打卡瓜分大奖!

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 基本介绍
    • 概述
      • 关键点
      • 应用实现
        • 数据库中的MVCC
          • Java中的CopyOnWriteArrayList
            • Nacos避免并发读写冲突问题
            相关产品与服务
            容器服务
            腾讯云容器服务(Tencent Kubernetes Engine, TKE)基于原生 kubernetes 提供以容器为核心的、高度可扩展的高性能容器管理服务,覆盖 Serverless、边缘计算、分布式云等多种业务部署场景,业内首创单个集群兼容多种计算节点的容器资源管理模式。同时产品作为云原生 Finops 领先布道者,主导开源项目Crane,全面助力客户实现资源优化、成本控制。
            领券
            问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档