ConcurrentHashMap的通俗解释

【转载 http://www.bootdo.com/blog/open/post/130

相信每个JAVA程序员都了解HashMap,最大的问题是线程不安全,因为方法中不涉及到同步,也正因为如此,HashMap的效率非常高,在不涉及线程安全的程序中广泛被应用。然而当涉及到多线程作业时,就会出现一些问题。为了解决这些问题JAVA提供了Hashtable,这是一种整体加锁的数据结构,然而效率不敢恭维。这时候就有了ConcurrentHashMap。

一个例子说明三者关系:
前提:某个卫生间共有16个隔间。

HashMap:每个隔间都没锁门,有人想上厕所,管理员指给他一个隔间,里面没人的话正常用,里面有人的话把这个人赶出来然后用。
优点,每个人进来不耽误都能用;缺点,每一个上厕所的人都有被中途赶出来的危险。

Hashtable:在卫生间外面安装一个大门,有人想上厕所,问管理员要一个钥匙进门,把门反锁用,用完后出来,把钥匙交换给管理员。在这个人上厕所期间,其他所有人都必须在外面排号。
优点,每个人都能安心上完厕所;缺点,卫生间外面可能已经出了人命。 =_=

ConcurrentHashMap:在卫生间每个隔间安装门锁,有人想上厕所,管理员指给他一个隔间,进来后这个隔间如果没人在用则直接用,如果有人正在用,则排号。在这期间其他人会按规则分到不同的隔间,重复上述行为。
优点:每个人都能安心上厕所,外面排队的也被均匀分摊。缺点:。。。

ConcurrentHashMap实现的原理
ConcurrentHashMap把Map分成了N个Segment(默认16),其中Segment是线程同步的,相当于分成了N个Hashtable。当实现Put方法时,在key值经过正常的hash后,还要再经过一次segmentForHash算法,用来分配具体防盗哪个Segment。后来的线程如果经过计算也是放在这个Segment下,则需要先获取锁,如果计算得出应该放在其他的Segment,则正常执行,不会影响效率,以此实现线程安全。ConcurrentHashMap使用锁分离技术,只要多个修改操作不发生在同一个Segment上,它们就可以并发进行。
有些方法需要跨段,比如size()和containsValue(),需要锁定整个表而而不仅仅是某个段,这需要按顺序锁定所有段,操作完毕后,又按顺序释放所有段的锁。这里“按顺序”是很重要的,否则极有可能出现死锁,在ConcurrentHashMap内部,段数组是final的,并且其成员变量实际上也是final的,但是,仅仅是将数组声明为final的并不保证数组成员也是final的,这需要实现上的保证。这可以确保不会出现死锁,因为获得锁的顺序是固定的。

参考资料

©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容

  • Java SE 基础: 封装、继承、多态 封装: 概念:就是把对象的属性和操作(或服务)结合为一个独立的整体,并尽...
    Jayden_Cao阅读 2,176评论 0 8
  • 从三月份找实习到现在,面了一些公司,挂了不少,但最终还是拿到小米、百度、阿里、京东、新浪、CVTE、乐视家的研发岗...
    时芥蓝阅读 42,422评论 11 349
  • 自加入亲子教育vip群以来,我可能是群里学习最慢、行动最慢的那一个了。刚入群时我想我跟我孩子的关系还可以,就...
    梦想成真无所不成阅读 303评论 3 3
  • 与传统语言相比,Forth的编译器过于简单。 传统的编译器通常设计成大型的程序,用来将可预见的合法的语法组织转换为...
    _火魂_阅读 1,014评论 0 0
  • 1月份的第一周已经过完,来到了第二周,我先来复盘一下第一周我自己的状况。 1. 对自己进行严厉并且深刻的谴责。在做...
    甜扁桃阅读 229评论 0 0