不了解这些“高级货”,活该面试当炮灰......

640?wx_fmt=gif

640?wx_fmt=jpeg

作者 | 中华石杉

责编 | 胡巍巍

本文经授权转载自石杉的架构笔记

“ 今天聊一个非常硬核的技术知识,给大家分析一下CopyOnWrite思想是什么,以及在Java并发包中的具体体现,包括在Kafka内核源码中是如何运用这个思想来优化并发性能的。

这个CopyOnWrite在面试的时候,很可能成为面试官的一个杀手锏把候选人给一击必杀,也很有可能成为候选人拿下Offer的独门秘籍,是相对高级的一个知识。

 

640?wx_fmt=png

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

 

大家可以设想一下现在我们的内存里有一个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();

}

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

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

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

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

 

640?wx_fmt=png

引入 CopyOnWrite 思想解决问题

 

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

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

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

很简单,顾名思义,利用“CopyOnWrite”的方式,这个英语翻译成中文,大概就是“写数据的时候利用拷贝的副本来执行”。

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

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

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

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

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

大家看下面的图,一起来体会一下这个过程:

640?wx_fmt=jpeg

关键问题来了,那那个写线程现在把副本数组给修改完了,现在怎么才能让读线程感知到这个变化呢?

关键点来了,划重点!这里要配合上volatile关键字的使用。

笔者之前写过文章,给大家解释过volatile关键字的使用,核心就是让一个变量被写线程给修改之后,立马让其他线程可以读到这个变量引用的最近的值,这就是volatile最核心的作用。

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

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

下面是JDK里的 CopyOnWriteArrayList 的源码。

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


 

 // 这个数组是核心的,因为用volatile修饰了

// 只要把最新的数组对他赋值,其他线程立马可以看到最新的数组

private transient volatile Object[] array;



public boolean add(E 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;



// 然后把副本数组赋值给volatile修饰的变量

           setArray(newElements);

return true;



       } finally {

           lock.unlock();

       }



   }

然后大家想,因为是通过副本来进行更新的,万一要是多个线程都要同时更新呢?那搞出来多个副本会不会有问题?

当然不能多个线程同时更新了,这个时候就是看上面源码里,加入了lock锁的机制,也就是同一时间只有一个线程可以更新。

那么更新的时候,会对读操作有任何的影响吗?

绝对不会,因为读操作就是非常简单的对那个数组进行读而已,不涉及任何的锁。而且只要他更新完毕对volatile修饰的变量赋值,那么读线程立马可以看到最新修改后的数组,这是volatile保证的。


 

private E get(Object[] a, int index) {



// 最简单的对数组进行读取

return (E) a[index];



   }

这样就完美解决了我们之前说的读多写少的问题。

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

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

 

640?wx_fmt=png

CopyOnWrite 思想在Kafka源码中的运用

 

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

话不多说,大家看下图:

640?wx_fmt=jpeg

这个时候Kafka的内存缓冲用的是什么数据结构呢?大家看源码:


 

private final ConcurrentMap<topicpartition, deque<="" span="">



          batches = new CopyOnWriteMap<TopicPartition, Deque>();

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

但是大家关注一点,他是自己实现了一个CopyOnWriteMap,这个CopyOnWriteMap采用的就是CopyOnWrite思想。

我们来看一下这个CopyOnWriteMap的源码实现:


 

   // 典型的volatile修饰普通Map

private volatile Mapmap;



@Override

public synchronized V put(K k, V v) {



// 更新的时候先创建副本,更新副本,然后对volatile变量赋值写回去

Mapcopy = new HashMap(this.map);

       V prev = copy.put(k, v);

this.map = Collections.unmodifiableMap(copy);

return prev;

   }



@Override

public V get(Object k) {



// 读取的时候直接读volatile变量引用的map数据结构,无需锁

return map.get(k);



   }

所以Kafka这个核心数据结构在这里之所以采用CopyOnWriteMap思想来实现,就是因为这个Map的key-value对,其实没那么频繁更新。

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

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

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

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

如果你能在面试时说清楚这个思想以及他在JDK中的体现,并且还能结合知名的开源项目Kafka的底层源码进一步向面试官进行阐述,面试官对你的印象肯定大大的加分。

如何挑战百万年薪的人工智能!

https://edu.csdn.net/topic/ai30?utm_source=csdn_bw

【END】

作为码一代,想教码二代却无从下手:

听说少儿编程很火,可它有哪些好处呢?

孩子多大开始学习比较好呢?又该如何学习呢?

最新的编程教育政策又有哪些呢?

下面给大家介绍CSDN新成员:极客宝宝(ID:geek_baby)

戳他了解更多↓↓↓

640?wx_fmt=jpeg

 热 文 推 荐 

☞ 一顿操作猛如虎!云原生应用为何如此优秀?

开了个会:破局企业云通信,华为加速 Buff 开发者!

☞ Google 究竟是不是要用 Fuchsia OS 取代 Android?

☞ 最全 Python 算法实现资源汇总!

@程序员,不加班就滚吧 | 程序员有话说

独家! 币安被盗原因找到了! 7074枚比特币竟是这样丢掉的

☞ 用对方法,开发与部署深度学习原来如此简单……

什么叫云原生应用?| 技术头条

☞ 补偿100万?Oracle裁900+程序员,新方案已出!

 

640?wx_fmt=png你点的每个“在看”,我都认真当成了喜欢

 

展开阅读全文

我的这些面试

07-04

06-04:尚酷软件,笔试,纯英文试题,网络理论、C++编程题分6-4开,写了76分的题,居然过了rnrn06-04:华平信息股份:口头笔试,题目很简单、基础,没下文rnrn06-13:一道上机编程题,答得很好,面试也谈得不错,周3、4、5晚加班到20:30(离住的地方远,照此得起早贪黑了),周六可能会加班(未必强制,估计是没加班费的),有月效绩奖,未来还能持股分红,根据之前在杭州的薪资计算、加上面试得也不错,开了8K,可惜的是:正式入职的话,(非技术出身的的总BOSS要求) 要将头发理短,所以第三天的offer就拒了 (理短我的头发,对谁也没有好处。。。除了我爸妈,谁说了也没用)rn再说下这家公司,这家公司属于一家创新型的公司,依据我的观察,在这里绝对不会无聊,绝对能迅速提高自己的技术,这个公司的活,我甚至觉得应该由腾讯、百度、华为。。。这样的大公司来做才合乎常情,甚至这个公司应该由国家来出钱。。。(利国利民)。。。 不过连头发都要管束的话,说明别的约束也不会少。。。。rn以上是个人的主观意识。。。未必如此。。。。rn值得大家去试试。。。rnrn06-14:尚酷软件,上机,类俄罗斯方块的游戏,修改BUG,补充功能,对游戏不是很感兴趣,没耐性(马上就是下家面试的时间),没过。。。 如果耐心地将代码全看一遍,兴许有希望能做好rnrn06-14:广联赛讯,做车联网的(嵌入式),(找门找了半天),网上的一套笔试题,技术经理面试的,感觉还可以,但没能拿到offer,要价太高?rnrn06-15:欧杰特,摄像机方案提供商,周六去面试的,周六隔周加班的,平日不加班,没谈成,一是薪资,二是,个人偏见(老板野心很大,谈未来时,说要把客户的客户抢过来,这话真不该对我这种人讲,我的错)rnrn06-17:正易龙邀请,棋牌游戏,没这能耐,婉拒rnrn06-19:邦彦信息技术邀请,音视频,没这能耐,婉拒rnrn06-20:华尊科技,又是编解码,没这能耐,婉拒rnrn06-25:星辰帷幄,安防,这是交通最便利的一次面试,这次没打的也找着公司了,面试很失望:rn “你看过《STL源码剖析》和《STL与泛型编程》是吧,那给我讲讲,STL到底是什么?”rn “我觉得,简单来讲就是数据结构与算法”rn “STL怎么会是数据结构与算法呢?”,感觉被怀疑是否真心了解过STLrn “平时模板用得多不多?”rn “有用到,但不多,场景需要的时候才会去用”rn “真正学会了模板,随便一行代码都可以写成模板”rn 我沉默了,想不到说什么,或者说,怎么说rn 继续,工作经验的介绍。。。rn “你在上家公司,是做底层的”rn “嗯,公共组件的开发,但是网络什么的都已经基本有现成的了,老版本移植过来的”rn “那你这个岗位的工作就没什么难度了”rn “嗯,是没多大难度”。。。rn “随便谁都可以做啊”rn “嗯。。。”,我再次沉默了rn 继续。。。rn “期望薪资是多少”rn “8K!”,其实我想说一万的,这里真心待不下去 (如果开1W又会是个什么情景)rn “8K?你什么都不会也开这么高,我们公司给不了”rn “这要看做什么了,薪资无所谓高低,最重要的是这个人是不是适合这个岗位,如果我是老板,我要的你什么也给不了,我2K也不会要你,何况面试双选的”我迫不及待想离开了rn “反正,你这个期望薪资我们是给不了的,今天就这样吧,如果有意,我们会再次联系你”rn “好的”,我挤出一抹微笑(虚伪)。。。。rnrn经过这次面试,自信心开始崩坏了,命运也开始转向了,再未收到面试(非外包的面试)rnrn07-01:软通动力的邀请,居然答应先了解下,(打电话时压力与理智持续着拉锯战,但是前期的打击帮了一把,所以,理智只能跪地求饶了,这是我第一次打电话时,感觉内心被分成两半,“欲拒还迎”?感觉那一刻变成了三个人:A君用卑微的口吻在和HR交谈,B君试图去阻止A君,C君在冷眼看着这个内心世界,真实感受,绝非鬼扯!)rnrn这晚上,想了很多,反省自己,说服自己,“从一个外包跳的另一家外包有什么意思,进去了,做一个项目又出来?”rnrn07-02:婉拒了软通动力的邀请rnrnrn现在很苦恼,因为,网上每天面试岗位都是那些,投递多少次都没反应!(人才热线,51job。。。)rn没有面试是很恐怖的。。。。rnrnrn现在又开始看opencv的教程(前段时间断了),努力不去想工作的事。。。rnrnrn很久没打电话回家了,这周打个回去吧。。。。rn 论坛

面试总结 —— 高级JAVA工程师】

03-02

近期考虑换工作的问题,于是投简历面试,面试5家公司的高级Java工程师,有4家给了我offer,想着总结一下面试经验,方便最近正在寻求机会的你们rnrn[color=#FF0000]一、无笔试题[/color]rn不知道是不是职位原因还是没遇到,面试时,都不需要做笔试题,而是填张个人信息表格,或者直接面试rnrn[color=#FF0000]二、三大框架方面问题[/color]rnrn[color=#FF9900]1、Spring 事务的隔离性,并说说每个隔离性的区别[/color]rn解答:[url=http://www.cnblogs.com/younggun/archive/2013/07/16/3193800.html]Spring事务详解[/url]rnrn[color=#FF9900]2、Spring事务的传播行为,并说说每个传播行为的区别[/color]rn解答:[url=http://www.cnblogs.com/younggun/archive/2013/07/16/3193800.html]Spring事务详解[/url]rnrn[color=#FF9900]3、hibernate跟Mybatis/ ibatis 的区别,为什么选择?[/color]rn解答:[url=http://blog.csdn.net/firejuly/article/details/8190229]Hibernate与 MyBatis的比较[/url]rnrn[color=#FF9900]4、struts跟spring mvc的优缺点,让你选会如何选[/color]rn解答:[url=http://blog.csdn.net/generalyy0/article/details/7003974]spring mvc与struts的区别[/url]rnrn[color=#FF9900]5、简单说说Spring 事务机制[/color]rn解答:[url=http://blog.csdn.net/pingnanlee/article/details/11488695]Spring事务机制[/url]rnrn[color=#FF9900]6、Spring 4.0新特性[/color]rn解答:[url=http://jinnianshilongnian.iteye.com/blog/1989381]Spring4新特性[/url]rnrn[color=#FF0000]三、负载均衡、集群相关[/color]rn[color=#FF9900]1、weblogic 负载均衡的原理和集群的配置[/color]rn解答:[url=http://blog.itpub.net/751371/viewspace-747988/]a、WEBLOGIC负载均衡原理 [/url] [url=http://blog.csdn.net/big1980/article/details/6291416]b、负载均衡和集群的配置(参考)[/url]rnrn[color=#FF9900]2、Nginx+Tomcat+Redis实现负载均衡、资源分离、session共享[/color] rn解答:[url=http://wenku.baidu.com/link?url=1rn43T_Fy5rHxwp3W2Sxs7yQngDWftWBYBtf3gtty3XPyTPbKHSrzUSlkyS9rk-Ctc11DV5M9ruD8C8UmyRortko2GKtlZzfB3hIzv0XPR3]参考配置[/url]rnrn[color=#FF9900]3、nginx配置文件详解——nginx.conf[/color]rn解答:[url=http://www.cnblogs.com/xiaogangqq123/archive/2011/03/02/1969006.html]Nginx配置文件详细说明[/url]rnrn[color=#FF0000]四、项目优化相关[/color]rn[color=#FF9900]1、web如何项目优化[/color]rn解答:这个我整理过一次,[url=http://bbs.csdn.net/topics/391849317]web项目性能优化(整理)[/url]rnrn[color=#FF9900]2、单例模式有几种? 如何优化?[/color]rn解答:[url=http://cantellow.iteye.com/blog/838473]单例模式的7种用法[/url]rnrn[color=#FF9900]3、简单说说线程池的原理和实现[/color]rn解答:[url=http://blog.csdn.net/hsuxu/article/details/8985931]线程池的原理和实现[/url]rnrn[color=#FF0000]五、并发和安全方面[/color]rn[color=#FF9900]1、项目并发如何处理?(我们是web项目)[/color]rn解答:[url=http://blog.csdn.net/y_h_t/article/details/6322823]高并发量网站解决方案[/url],另外,还有数据库乐观锁,数据库读写分离、使用消息队列、多用存储过程等等rnrn[color=#FF9900]2、简单说说功能权限存在的水平权限漏洞和垂直权限漏洞的场景和解决办法(因为我们目前权限级别就是功能权限)[/color]rn解答:rnA、水平权限漏洞,如下图rn[img=https://img-bbs.csdn.net/upload/201603/02/1456914143_812722.png][/img]rn假设机构有 用户A和用户B 两个用户,其中A有1、2和3权限 , 用户B有 2 和3 的权限,这时候假设用户B 知道1,并给自己添加1的权限,这时候就是水平权限漏洞。rn目前解决办法:[color=#FF00FF]1、限制入口,让用户B无法编辑自己的权限 2、对用户B无法进行向上扩展[/color]。最根本的解决办法是深入到数据权限rn[url=http://www.bubuko.com/infodetail-196677.html]水平权限漏洞和解决办法[/url]rnrnB、垂直权限漏洞rn[url=http://www.wooyun.org/bugs/wooyun-2010-057371]垂直权限案例和解决方案[/url]rnrn[color=#FF9900]3、平台上的图片如何防盗链[/color]rn解答:[url=http://blog.sina.com.cn/s/blog_701635160100l5hn.html]http下载防盗链原理:http协议的字段referer 记录来实现[/url]rnrn[color=#FF9900]4、如何区分上传的图片是不是木马?[/color]rn解答:1、看上传的图片后缀 2、如何后缀是篡改的,那么每个文件有个魔术数字[url=http://blog.csdn.net/fenglibing/article/details/7733496]文件上传-魔术数字[/url]rnrn[color=#FF9900]5、消息队列的原理和实现[/color]rn解答:[url=http://blog.csdn.net/blade2001/article/details/5193464]1、消息队列原理 [/url] 2、[url=http://blog.csdn.net/jwdstef/article/details/17380471]深入浅出 消息队列 ActiveMQ[/url]rnrn[color=#FF0000]六、数据库方面[/color]rn[color=#FF9900]1、mysql查询字段区不区分大小写?[/color]rn解答:不区分,哪怕值也不区分(我当时还反问了,区不区分大小的应用含义有哪些,面试官没说得出来)rnrn[color=#FF9900]2、简单说说数据库集群和负载均衡、分布式(我不懂这块)[/color]rn解答:[url=http://www.cnblogs.com/CareySon/p/3627594.html]负载均衡和集群参考[/url] , [url=http://bbs.csdn.net/topics/390080620]参考2[/url]rnrn[color=#FF9900]3、存储过程的结构和优点[/color]rn解答:[url=http://zhidao.baidu.com/link?url=uJqI3GqyZyVvtK33KXijtTUHfv9rVtis3vkVs3z42gRGjgQrhhuNlu4pxYjCp7Mfzr9GkpLEKn-rqGc1qs-0Cq]大概结构[/url] rn[url=http://blog.csdn.net/jackmacro/article/details/5688687]存储过程的优缺点[/url]rnrn[color=#FF9900]4、触发器的原理和作用[/color]rn解答:[url=http://wenku.baidu.com/link?url=MPPVmAKSosAF1tRshVi9gWRfZ3Lb671JJWlOm9iW9TbpObaFhKrcF5YI_JB4Mp_s2dXxJcmGSASL1emFc5TX02spVDq61mkZcdVjtHZR2J7]参考[/url]rnrnrn好了,先总结到这里,还有很多忘了,也有一些不好怎么表达,仅供大家参考,勿喷~ 论坛

没有更多推荐了,返回首页