HashMap与ConcurrentHashMap

HashMap

HashMap是Map接口的一个实现,用于存储键值对的集合。其主体是一个数组,数组初始值为null。

put方法

调用HashMap的put方法存入键值对时,首先调用hash函数对键值对的key进行哈希运算,结果为存储该键值对的数组index。但数组空间有限,当键值对足够多时,再完美的hash函数也可能生成冲突的index。为解决该问题,每个数组元素除了存储键值对,还会存储next指针,当多个键值对通过hash函数映射到数组同一个index时,即组成一个链表。

Get方法

调用hashMap的get方法根据key查找时,首先调用hash函数计算key对应的hash值,也就是数组index;如果该index对应多个entry,那么遍历链表寻找key对应的entry。之所以链表采用头节点插入法,是因为hashmap的设计者认为后插入的键值对查找几率更高。

hashMap数组长度

数组的默认初始长度为16,每次自动扩展或手动初始化是都需要是2的幂。选择16,是为了得到一个尽量均匀分布的hash函数,hash函数采用位运算,如下:index =  HashCode(Key) &  (Length - 1)。当长度为16或者2的幂时,长度-1的二进制各位都是1。这样更有利于实现均匀分布。

举例:book的hashcode,结果为十进制的3029737,二进制的101110001110101110 1001;Length-1的结果为十进制的15,二进制的1111;与运算,101110001110101110 1001 &1111 = 1001,十进制是9,所以 index=9。

举例:如果数组长度为10,10-1=9,其二进制为1001,那么1111,1001与1001进行与运算的结果是一样的,都是1001,也就违背了均匀分布的目的。

HashMap的扩容Resize

HashMap的容量是有限的。当经过多次元素插入,HashMap达到一定饱和度时,Key映射位置发生冲突的几率会逐渐提高。这时HashMap需要扩展它的长度,也就是进行Resize。衡量HashMap是否进行Resize的条件如下:HashMap.Size   >=  Capacity * LoadFactor;loadFactor是负载因子,默认情况下为0.75。

HashMap的扩容包括两步,第一步是创建一个原有数组两倍大小的新数组;第二步是把原有数组的键值对重新进行哈希运算并根据计算得到的index值保存在新数组。第二步又称为rehash

高并发下的HashMap

rehash的过程并非线程安全。假设一个HashMap已经到了Resize的临界点。此时有两个线程A和B,在同一时刻对HashMap进行Put操作,此时达到Resize条件,两个线程各自进行Rezie的第一步,也就是扩容:并且进行rehash,rehash的过程中多线程可能导致链表中出现环,导致死循环。避免HashMap的线程安全问题,有多种方法,比如HashTable或者synchronisedMap,但二者存在性能问题,无论是读操作还是写操作,他们都会给整个集合加锁,使得同一时间的其他操作都被堵塞。因此在高并发场景下,通常使用ConcurrentHashMap,来兼顾线程安全与性能。

ConcurrentHashMap

相对于HashMap,ConcurrentHashMap的关键词是segment。一个concurrentHashMap包含若干个segment,类似数据库的水平扩展,把map中的数据分散在若干个segment;每个segment拥有和HashMap一样的结构。每个segment独立加锁,在保证线程安全的同时降低了锁的粒度,让并发操作效率更高。

不同segment的并发写入
同一个segment的读写操作可以同时发生
segment的写操作需要上锁,因此同时对一个segment进行写操作会被加锁/阻塞

在ConcurrentHashMap执行Get方法:根据key进行二次Hash运算,先定位到segment,再定位到segment中的entry:1.为输入的Key做Hash运算,得到hash值。2.通过hash值,定位到对应的Segment对象3.再次通过hash值,定位到Segment当中数组的具体位置。

在ConcurrentHashMap执行Put方法:1.为输入的Key做Hash运算,得到hash值。2.通过hash值,定位到对应的Segment对象。3.获取可重入锁。4.再次通过hash值,定位到Segment当中数组的具体位置。5.插入或覆盖HashEntry对象。6.释放锁。

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 217,406评论 6 503
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,732评论 3 393
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 163,711评论 0 353
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,380评论 1 293
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,432评论 6 392
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,301评论 1 301
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,145评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,008评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,443评论 1 314
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,649评论 3 334
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,795评论 1 347
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,501评论 5 345
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,119评论 3 328
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,731评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,865评论 1 269
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,899评论 2 370
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,724评论 2 354

推荐阅读更多精彩内容