HashMap(1)

 HashMap的原理和问题:

         First.      基本原理

        Second. HashMap的初始长度,以及原因

        Third.     loadFactor以及resize

        Fourth.    高并发下的死锁问题


First,some fundamental theory:

     1.hashMap存储的是key-value的键值对集合。

       每一个键值对也叫Entry,Entry分散分布在一个数组里。比如说这里的hashMap的一个实例x对应的数组a长度为6.

     2.put和get方法:

       (1)put

       比如说x.put("apple",0),就是一个Entry,记作entryOne。

       在放入entryOne之前,我们要知道究竟放在数组a的哪个位置。在这里要先计算index=Hash("apple"),我们暂时不管怎么计算,如果最终index=2的话,那么entryOne就放在a[2]处。

       那么就有一个问题,因为a的长度有限,再放入别的Entry的时候会不会和前面所放的冲突,答案是会的。此时怎么解决这个问题呢?

       java选择开辟链表法,也就是说在发生冲突的位置用链表的形式存储index为该位置的Entries.比如说x.put("orange",1),index=Hash("orange")=2,把记作entryTwo。此时a[2]处的头节点为entryTwo,然后entryTwo指向entryOne。至于为什么后放入的要放在头部(头部插入),这是因为往往新插入的被访问的几率更高。

       (2)get

       我们根据key,在hashMap x中找到相应的Entry。

       同理,比如找“apple”,同样计算index=Hash("apple")=2,但就在a[2]处我们发现了一个链表,依次遍历直到找到Entry y,使得y.key==apple,或者没找到,返回null。

Second,the initial length of capacity and the reason

       java的hashMap的初始长度为16,2的4次方:

/*** The default initial capacity - MUST be a power of two.*/

static final int DEFAULT_INITIAL_CAPACITY = 1 << 4; // aka 16

    以上是源码的初始化,但为什么说初始的容量必须是2的幂次呢?

    我们上面提到计算index=Hash("key"),具体我们是怎么计算的呢?

    实际上,index=Hash("key")=HashCode("key")%length.这里HashCode("key")是key对应的哈希码,至于怎么产生的后面再介绍。

那么对于index=Hash("key")的映射函数,我们希望这个hash函数尽量分布均匀。

    另外,由于取模运算效率极低,hashMap的开发者使用的是位运算。

    有:index=HashCode(key)&(length-1);

    为了具体说明,比如说apple的hashCode为xxxxxxxxxxxxx1001(高位值不影响结果),hashMap的length初始值为16,length-1=15=1111。则,结果为1001。其实就是保留hashCode的低位,由于是&运算,只有length-1为全1时保留的最多,结果最均匀。

我们可以假设length=10,length=9=1001,xxxxxxxxxxxxx1111和xxxxxxxxxxxxx1001

结果都为1001,实际上x11x的情况根本不会出现。这会导致,hashMap的一些位置根本就没有entry,而别的位置挤满了entry。  

 Third.     loadFactor  and resize the hashMap

   我们知道哪怕再平均的hash映射函数,只要插入的数据够多,就会影响速度,这个时候就要扩大hashMap,我们把扩大的过程叫做resize。另一方面,什么时候我们决定resize呢?换句话说,插入的数据多到什么程度我们resize hashMap呢?这取决于loadFactor,在java的hashMap中取其为0.75。

/*** The load factor used when none specified in constructor.*/

static final float DEFAULT_LOAD_FACTOR = 0.75f;

至于为什么是0.75,开发者在一开始就给出了解释:

As a general rule, the default load factor (.75) offers a good tradeoff between time and space costs.  Higher values decrease the space overhead but increase the lookup cost (reflected in most of the operations of the HashMap class, including get and put).

这是时间和空间代价的平衡点。

而resize所做的操作则是,在插入占到0.75以上时,HashMap使用新数组代替旧数组,对原有的元素根据hash值重新就算索引位置,重新安放所有对象。

要注意!之前的链表在resize之后,相当于反序了,因为resize遍历的过程从头到尾将entry放入新的hashMap中,而且是头部插入。


Fourth.  deadlock caused by high concurrency 

为什么高并发下hashMap容易出现死锁?就是resize的问题,当hashMap处于阈值,也就是即将被扩容,如果此时有两个进程同时对其resize,因为hashMap是没有加锁机制的。因为resize遍历的过程从头到尾将entry放入新的hashMap中,而且是头部插入。没有链表存在还好,一旦有链表存在,极易形成环链。

    比如说同一index下的链表中有a,b,进程1此时e指向a,e.next指向b,进程2此时e指向b,e.next指向a。如此执行下去新的hashMap就会产生环链。

    有人向Sun公司反映,然而人家说了,这本来就不是给多线程使用的,想保证线程安全自己用concurrentHashMap去。

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

推荐阅读更多精彩内容

  • 1.HashMap是一个数组+链表/红黑树的结构,数组的下标在HashMap中称为Bucket值,每个数组项对应的...
    谁在烽烟彼岸阅读 1,025评论 2 2
  • 实际上,HashSet 和 HashMap 之间有很多相似之处,对于 HashSet 而言,系统采用 Hash 算...
    曹振华阅读 2,513评论 1 37
  • 【邂逅崇高灵魂】一对英国爱丁堡老夫妇准备卖了房到西班牙去养老,老人在西班牙看中了房子,两周内必须付款,就在爱丁堡的...
    太极涛歌阅读 247评论 0 0
  • 郭芳艳 焦点网络初级五期 坚持原创分享第151天 在儿童教育中,欣赏和不许犯错是无法兼容的两种态度,不...
    冰山蓝鹰阅读 76评论 0 0
  • 对源表数据进行预导入,先导入前几条数据,目的是为了获取时间参照。 整个转换预览 获取目标表的目前的最大时间 表输入...
    夏无忧阳阅读 1,425评论 0 0