29 | Copy-on-Write模式:不是延时策略的COW
王宝令
该思维导图由 AI 生成,仅供参考
在上一篇文章中我们讲到 Java 里 String 这个类在实现 replace() 方法的时候,并没有更改原字符串里面 value[]数组的内容,而是创建了一个新字符串,这种方法在解决不可变对象的修改问题时经常用到。如果你深入地思考这个方法,你会发现它本质上是一种 Copy-on-Write 方法。所谓 Copy-on-Write,经常被缩写为 COW 或者 CoW,顾名思义就是写时复制。
不可变对象的写操作往往都是使用 Copy-on-Write 方法解决的,当然 Copy-on-Write 的应用领域并不局限于 Immutability 模式。下面我们先简单介绍一下 Copy-on-Write 的应用领域,让你对它有个更全面的认识。
Copy-on-Write 模式的应用领域
我们前面在《20 | 并发容器:都有哪些“坑”需要我们填?》中介绍过 CopyOnWriteArrayList 和 CopyOnWriteArraySet 这两个 Copy-on-Write 容器,它们背后的设计思想就是 Copy-on-Write;通过 Copy-on-Write 这两个容器实现的读操作是无锁的,由于无锁,所以将读操作的性能发挥到了极致。
除了 Java 这个领域,Copy-on-Write 在操作系统领域也有广泛的应用。
公开
同步至部落
取消
完成
0/2000
荧光笔
直线
曲线
笔记
复制
AI
- 深入了解
- 翻译
- 解释
- 总结
Copy-on-Write模式是一种写时复制的技术,广泛应用于Java中的不可变对象、操作系统、函数式编程等领域。在Java中,Copy-on-Write容器如CopyOnWriteArrayList和CopyOnWriteArraySet实现了无锁的读操作,适用于读多写少的场景。在操作系统领域,Copy-on-Write被用于提升性能,如Linux中的fork()函数以及文件系统Btrfs和aufs。此外,Copy-on-Write还在Docker容器镜像、Git等领域有应用。在函数式编程中,由于基于不可变性,所有修改操作都需要Copy-on-Write来解决。尽管Copy-on-Write会消耗内存,但随着硬件性能的提升和自动垃圾回收算法的成熟,内存消耗已经可以接受。因此,对于写操作较少的场景,可以尝试使用Copy-on-Write来提升性能。文章还提到了一个真实案例,展示了如何使用CopyOnWriteArrayList和CopyOnWriteArraySet来实现路由表,以及如何设计Router类以适应Copy-on-Write模式。总的来说,Copy-on-Write是一种简单且通用的并发解决方案,在多个领域都有着广泛的应用。
仅可试看部分内容,如需阅读全部内容,请付费购买文章所属专栏
《Java 并发编程实战》,新⼈⾸单¥59
《Java 并发编程实战》,新⼈⾸单¥59
立即购买
© 版权归极客邦科技所有,未经许可不得传播售卖。 页面已增加防盗追踪,如有侵权极客邦将依法追究其法律责任。
登录 后留言
全部留言(56)
- 最新
- 精选
- 假行僧没有提供CopyOnWriteLinkedList是因为linkedlist的数据结构关系分散到每一个节点里面,对每一个节点的修改都存在竟态条件,需要同步才能保证一致性。arraylist就不一样,数组天然的拥有前驱后继的结构关系,对列表的增删,因为是copy on wirte,所以只需要cas操作数组对象就能够保证线程安全,效率上也能接受,更重要的是避免锁竞争带来的上下文切换消耗。有一点需要注意的是CopyOnWriteArrayList在使用上有数据不完整的时间窗口,要不要考虑需要根据具体场景定夺
作者回复: 👍
2019-05-0515131 - 欢乐小熊我对课后的思考是这样的, ArrayList 是用是数组实现的, 在内存上时一块连续的区域, 拷贝时效率比较高, 时间复杂度为 O(1) LinkedList 是链表实现, 其数据是通过指针串联起来的, 并非一块连续的区域, 拷贝时必须要进行遍历操作, 效率比较低, 时间复杂度是 O(n)
作者回复: 👍
2019-09-2965 - 夏天王老师,问一个单例模式的问题: 在双重检查加锁的单例模式中 需不需要加 volatile 关键字修饰? 自己的理解:是需要。但是我在考虑其中的锁是不是存在happen before规则,不用加volatile也能保证可见性?
作者回复: 必须加,还有指令重排问题
2019-05-06612 - 刘infoq服务下线了,如果数据不一致,会不会有请求发到下线了的服务器
作者回复: rpc的客户端和服务提供端会建立一个长连接,定时发心跳,并不完全依赖注册中心的数据。很多rpc的服务端提供了手动下线功能,能解决你说的这个问题
2019-05-1027 - DFighting主要是ArrayList的数据存储是数组,复制可能只需要移动一个内存页或者多个连续的内存空间就可以,而且数组在复制的时候是知道数据集的大小的(动态扩容后也还是数组,只是预先申请了一些未来使用的空间),而LinkdList底层实现为使用Node<?>链表,存储位置分散且大小不可控,如果使用COW可能会适得其反。这应该也是一种用空间换时间的策略吧。这么来看,除非事先限定了数据的存储区域,不然用COW还是数组方便些吧。
作者回复: 👍
2019-09-285 - 与路同飞redis中的快照rdb复制也是基于COW的
作者回复: 👍🏻
2020-08-144 - 静水流深大师好不容易写了个CopyOnWriteArrayList,再写一个CopyOnWriteLinkedList 他觉得没必要。他也累:)
作者回复: 😂
2019-09-263 - 张三上一篇说包装类型、String 是享元模式,这篇说是Copy-on-Write,是两种模式都有吗?
作者回复: 都有
2019-05-062 - 1620数组在内存地址是连续的,天然适合copy,链表是分散的。
作者回复: 👍
2019-10-151 - yangSting Long … 居然可以和CoW、Lock联系起来! 跟着老师默默修行! 希望这个专栏永远不要停! 能希望能一直看到老师写的专栏!
作者回复: 感谢捧场😂
2019-05-131
收起评论