面试官的杀手锏-CopyOnWrite

2024-02-26 18:59

本文主要是介绍面试官的杀手锏-CopyOnWrite,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

今天聊一个非常硬核的技术知识,给大家分析一下CopyOnWrite思想是什么,以及在Java并发包中的具体体现,包括在Kafka内核源码中是如何运用这个思想来优化并发性能的。
这个CopyOnWrite在面试的时候,很可能成为面试官的一个杀手锏把候选人给一击必杀,也很有可能成为候选人拿下Offer的独门秘籍,是相对高级的一个知识。
CopyOnWrite是什么意思呢?很简单,顾名思义,利用“CopyOnWrite”的方式,这个英语翻译成中文,大概就是“写数据的时候利用拷贝的副本来执行”。

1、读多写少的场景下引发的问题?

大家可以设想一下现在我们的内存里有一个ArrayList,这个ArrayList默认情况下肯定是线程不安全的,要是多个线程并发读和写这个ArrayList可能会有问题。

好,问题来了,我们应该怎么让这个ArrayList变成线程安全的呢?

有一个非常简单的办法,对这个ArrayList的访问都加上线程同步的控制。

比如说一定要在synchronized代码段来对这个ArrayList进行访问,这样的话,就能同一时间就让一个线程来操作它了,或者是用ReadWriteLock读写锁的方式来控制,都可以。

我们假设就是用ReadWriteLock读写锁的方式来控制对这个ArrayList的访问。
这样多个读请求可以同时执行从ArrayList里读取数据,但是读请求和写请求之间互斥,写请求和写请求也是互斥的。

大家看看,代码大概就是类似下面这样:

public Object read() {lock.readLock().lock();// 对ArrayList读取lock.readLock().unlock();
}public void write() {lock.writeLock().lock();// 对ArrayList写lock.writeLock().unlock();}

大家想想,类似上面的代码有什么问题呢?

最大的问题,其实就在于写锁和读锁的互斥。假设写操作频率很低,读操作频率很高,是写少读多的场景。

那么偶尔执行一个写操作的时候,是不是会加上写锁,此时大量的读操作过来是不是就会被阻塞住,无法执行?

这个就是读写锁可能遇到的最大的问题。

2、引入 CopyOnWrite 思想解决问题

这个时候就要引入CopyOnWrite思想来解决问题了。

他的思想就是,不用加什么读写锁,锁统统给我去掉,有锁就有问题,有锁就有互斥,有锁就可能导致性能低下,你阻塞我的请求,导致我的请求都卡着不能执行。

那么他怎么保证多线程并发的安全性呢?

在读数据的时候,其实不加锁也没关系,大家左右都是一个读罢了,互相没影响。

问题主要是在写的时候,写的时候你既然不能加锁了,那么就得采用一个策略。

假如说你的ArrayList底层是一个数组来存放你的列表数据,那么这时比如你要修改这个数组里的数据,你就必须先拷贝这个数组的一个副本。

然后你可以在这个数组的副本里写入你要修改的数据,但是在这个过程中实际上你都是在操作一个副本而已。

这样的话,读操作是不是可以同时正常的执行?这个写操作对读操作是没有任何的影响的吧!

大家看下面的图,一起来体会一下这个过程:
在这里插入图片描述
关键问题来了,那那个写线程现在把副本数组给修改完了,现在怎么才能让读线程感知到这个变化呢?

关键点来了,划重点!这里要配合上volatile关键字的使用。
给大家解释过volatile关键字的使用,核心就是让一个变量被写线程给修改之后,立马让其他线程可以读到这个变量引用的最近的值,这就是volatile最核心的作用。

所以一旦写线程搞定了副本数组的修改之后,那么就可以用volatile写的方式,把这个副本数组赋值给volatile修饰的那个数组的引用变量了。

只要一赋值给那个volatile修饰的变量,立马就会对读线程可见,大家都能看到最新的数组了。

下面是JDK里的 CopyOnWriteArrayList 的源码。

大家看看写数据的时候,他是怎么拷贝一个数组副本,然后修改副本,接着通过volatile变量赋值的方式,把修改好的数组副本给更新回去,立马让其他线程可见的。下面是JDK里的 CopyOnWriteArrayList 的源码。

大家看看写数据的时候,他是怎么拷贝一个数组副本,然后修改副本,接着通过volatile变量赋值的方式,把修改好的数组副本给更新回去,立马让其他线程可见的。
在这里插入图片描述
这样就完美解决了我们之前说的读多写少的问题。

如果用读写锁互斥的话,会导致写锁阻塞大量读操作,影响并发性能。

但是如果用了CopyOnWriteArrayList,就是用空间换时间,更新的时候基于副本更新,避免锁,然后最后用volatile变量来赋值保证可见性,更新的时候对读线程没有任何的影响!

3、CopyOnWrite 思想在Kafka源码中的运用

在Kafka的内核源码中,有这么一个场景,客户端在向Kafka写数据的时候,会把消息先写入客户端本地的内存缓冲,然后在内存缓冲里形成一个Batch之后再一次性发送到Kafka服务器上去,这样有助于提升吞吐量。

话不多说,大家看下图:
在这里插入图片描述
这个时候Kafka的内存缓冲用的是什么数据结构呢?大家看源码:

private final ConcurrentMap<topicpartition, Deque>
batches = new CopyOnWriteMap<TopicPartition, Deque>();

这个数据结构就是核心的用来存放写入内存缓冲中的消息的数据结构,要看懂这个数据结构需要对很多Kafka内核源码里的概念进行解释,这里先不展开。

但是大家关注一点,他是自己实现了一个CopyOnWriteMap,这个CopyOnWriteMap采用的就是CopyOnWrite思想。
这个CopyOnWriteMap的源码实现如下:
在这里插入图片描述
所以Kafka这个核心数据结构在这里之所以采用CopyOnWriteMap思想来实现,就是因为这个Map的key-value对,其实没那么频繁更新。

也就是TopicPartition-Deque这个key-value对,更新频率很低。

但是他的get操作却是高频的读取请求,因为会高频的读取出来一个TopicPartition对应的Deque数据结构,来对这个队列进行入队出队等操作,所以对于这个map而言,高频的是其get操作。

这个时候,Kafka就采用了CopyOnWrite思想来实现这个Map,避免更新key-value的时候阻塞住高频的读操作,实现无锁的效果,优化线程并发的性能。

相信大家看完这个文章,对于CopyOnWrite思想以及适用场景,包括JDK中的实现,以及在Kafka源码中的运用,都有了一个切身的体会了。

这篇关于面试官的杀手锏-CopyOnWrite的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/749839

相关文章

【吊打面试官系列-Redis面试题】说说 Redis 哈希槽的概念?

大家好,我是锋哥。今天分享关于 【说说 Redis 哈希槽的概念?】面试题,希望对大家有帮助; 说说 Redis 哈希槽的概念? Redis 集群没有使用一致性 hash,而是引入了哈希槽的概念,Redis 集群有 16384 个哈希槽,每个 key 通过 CRC16 校验后对 16384 取模来决定放置哪个槽, 集群的每个节点负责一部分 hash 槽。

面试官:synchronized的锁升级过程是怎样的?

大家好,我是大明哥,一个专注「死磕 Java」系列创作的硬核程序员。 回答 在 JDK 1.6之前,synchronized 是一个重量级、效率比较低下的锁,但是在JDK 1.6后,JVM 为了提高锁的获取与释放效,,对 synchronized 进行了优化,引入了偏向锁和轻量级锁,至此,锁的状态有四种,级别由低到高依次为:无锁、偏向锁、轻量级锁、重量级锁。 锁升级就是无锁 —>

【Unity面经】实习篇:面试官常问的一百个面试题

👨‍💻个人主页:@元宇宙-秩沅 👨‍💻 hallo 欢迎 点赞👍 收藏⭐ 留言📝 加关注✅! 👨‍💻 本文由 秩沅 原创 👨‍💻 专栏交流🧧🟥Unity100个实战基础✨🎁🟦 Unity100个精华一记✨🎁🟩 Unity50个demo案例教程✨🎁🟨 Unity100个精华细节BUG✨🎁🟨 Unity100个面试题✨🎁 文章

作为面试官的一点点感悟,谈谈技术人的成长之路

因为工作上的原因,做过几次面试官,面试的同学有应届生,也有工作3-5年的老技术人。最近也频繁作为面试官帮助筛选候选人,中间有很多值得深思的东西,我记录了下来分享给大家。 以下观点仅为个人观点,不代表任何公司的立场。        01 面试不是简单的你问我答 一般来讲,作为面试官和候选人进行沟通的第一个问题是一般是自我介绍,整个自我介绍的情况应该控制在2分钟左右,阐述自己的教育背景,项目经历

【对线面试官】阿里面试经历,有些人走一步看一步就挂了

点击上方蓝色字体,选择“设为星标” 回复”资源“获取更多资源 这个其实说来就话长了。是小编曾经面试阿里妈妈的经历。 这次面试最终在HR面挂掉,以至于后面回忆起来,仍然是一桩美谈。 这次面试长达一个月之久,共经历了4轮技术面,1轮HR。前四轮面试过关斩将,简直开了挂一般,跟面试官正面对线,丝毫不虚。听我一一道来。 第一轮 第一面是电话面试,晚上10点半。我特么一脸问号?你们这是刚加完班吧?事实上我

【大数据哔哔集20210122】面试官问我HDFS丢不丢数据?我啪就把这个文章甩到他脸上

数据一致性 HDFS作为分布式文件系统在分布式环境下如何保证数据一致性。HDFS中,存储的文件将会被分成若干的大小一致的block分布式地存储在不同的机器上,需要NameNode节点来对这些数据进行管理,存储这些block的结点称为DataNode,NameNode是用来管理这些元数据的。 NameNode保证元数据的一致性 客户端上传文件时,NameNode首先往edits log文件

几乎每一位面试官都会关注的能力,你做到了吗?

又到了金九银十招聘季,虽然说大环境不好,但对于不少想要挪窝的同学来说,这个时间段还是一个不错的窗口期。 我也借此机会在Boss上看了不少岗位,发现很多岗位JD都有一条关于“功能设计规范”的要求。 相比较于设计岗的设计规范原则,产品岗的设计规范会要求你对业务、产品有更强的纵深性,但这种基础且重要的能力被太多人忽视了。 因此,我列举了以下11点产品设计规范,同学们可以自查一下看看日常有没有做到

J.U.C Review - CopyOnWrite容器

文章目录 什么是CopyOnWrite容器CopyOnWriteArrayList优点缺点源码示例 仿写:CopyOnWriteMap的实现注意事项 什么是CopyOnWrite容器 CopyOnWrite容器是一种实现了写时复制(Copy-On-Write,COW)机制的并发容器。在并发场景中,多个线程可能同时访问同一资源,当某个线程需要修改数据时,系统会创建该数据的副本供

魔鬼面试官:用户在电商网站中购买成功了,那么它在微服务中经历了什么?...

点击上方“朱小厮的博客”,选择“设为星标” 做积极的人,而不是积极废人 面试的时候,面试官问:用户在电商网站中购买成功了,那么它在微服务中经历了什么?你该如何作答?  当我傻啊,用户在电商网站购买成功,还在微服务中,那肯定就是有一套微服务架构的电商系统。 设计一套电商系统还不简单?简单想象一下,既然是一个电商系统,有用户去购买,就肯定得有一个用户模块,购买什么东西总不是西北风吧,购买肯定是

我在阿里做了10年技术面试官,这7个些建议能让你受益终身

我可能是在同龄人中做面试官经验比较丰富的,在某乎实习的时候就参与了Java的技术面试。后来在阿里以及另一家公司也面试过不少候选人,校招、社招、外包都有面试过。这里以一个面试官的角度来给大家谈谈在面试的时候怎么能给面试官留下更好的印象,更容易拿到大厂的Offer。为了不造成任何面试题泄露,这里我不会涉及到任何具体的面试题。 1、社招和校招的面试重点 社招其实和校招的面试重点有一些区别,以Java