Map数据结构

1、HashMap

1.1    HashMap结构

JDK1.7和JDK1.8的结构不同

在JDK1.7中,key和value构成Entry节点,所有的Entry节点构建一个数组,数组的下标是key的HashCode取模。另外,对于hashCode一样但是key值不一样的元素,会放在同一个Entry节点中,并且他们在这个Entry节点内部会构成一个单向链表。

在JDK1.8中,key和value组成Node节点,所有的Node节点构建一个数组,数组的下标是key的HashCode取模。这个跟JDK1.7一样。但是在Node节点内部就不一样了,如果Node节点内的元素小于等于8个,还是跟JDK1.7一样是单向链表结构,如果大于8个元素,就会自动变成红黑树结构。红黑树结构比链表结构的时间复杂度要低,直接提升了性能。


1.2    HashMap细节

HashMap允许有一条空数据。

HashMap中Node数组的初始长度是16,并且后面自动扩容的长度也是2的幂数。

HashMap中元素放在数组的哪个位置(下标)是计算出来的:

1)先把元素的key取hashcode,得到一个值;

2)然后把这个值用hashMap自己的HashCode()方法再取一遍Hash值,目的是为了让这个值的0和1尽量分散;

3)最后把这个值跟(数组长度-1,也就是11111111111)做&运算,得到一个小于数组长度的值。这个值就是放的位置。

1.3    HashMap扩容机制

HashMap必须同时满足两个条件才会扩容:

1)存放新值的时候当前已有元素的个数必须大于等于阈值(数组长度*负载因子0.75)

2)存放新值的时候当前存放数据发生hash碰撞(当前key计算的hash值换算出来的数组下标位置已经存在值)

1.4    HashMap Resize

Resize()方法用来给hashMap扩容,扩容的时机在上面讲了,下面讲的是扩容的方法:

1)首先,计算需要扩容的新NODE数组的长度,是扩容2倍,还是几倍。

2)然后,重新申明一个新的NODE数组,长度是计算好的值 ;

3)所有元素重新计算hashcode,复制到新的位置。不仅包括NODE数组的位置移位,还包括单向链表和红黑树节点的数据移位。

1.5    HashMap死锁原因

HashMap死锁,体现了HashMap的线程不安全性,是无法避免的,原因是:

如果两个线程都刚好同时碰到了HashMap需要扩容的时机,扩容时HashMap需要做rehash,重新生成新数据,那么两个线程分别往新的Node数组里放元素的时候,由于多线程并发执行的原因,可能出现链表中元素的next节点互相是对方节点的情况,导致死锁。

1.6    ConCurrentHashMap

JDK1.7与JDK1.8实现方式完全不同,一个是分段锁,一个是对node加锁。

1)JDK1.7实现:

是线程安全的,区别于hashtable,concurrenthashmap是将数据分成多个段,每个段分别加锁,也就是段锁。而hashtable是对数据整个加锁,两者效率明显不一样,对segment加锁的话,其它segment的数据还能继续操作。

Concurrenthashmap的put操作、get操作、remove操作都下放到每一个segment里面去操作的。我们通过对插入数据的key的hashcode再进行一次hash,得到segment的值,从而确定每一个key所在的segment。

至于Count计数方法,则是把每个segment里面的count相关,得到全部值的和。

2)JDK1.8实现

相对于JDK1.7进行了两点改变,分别是:

——取消了segmant,而是采用transient volatile HashEntry table[]保存数据,对table数组的每个Node加锁,粒度更小,即实现了线程安全,又提高了性能;

——同JDK1.8Hashmap的改变,Node内部结构支持单向链表+红黑树两种存储结构,提高查询效率。

2、   LinkedhashMap

是双向链表的hashmap,也是有序的hashmap。HashMap存进去的数据取出来是没顺序的,但是linkedHashMap是有顺序的。

LinkedHashMap的顺序可以有两种,一种是按插入顺序排序的,一种是按照操作顺序排序的。

因此,如果需要实现LRU(最近最少使用),只需要使用LinkedHashMap的按操作顺序排序方式,最近使用的在LinkedHashMap的链表头位置,最久没使用的在链表尾位置。

2.1    ConcurrentLinkedHashMap

是LinkedHashMap的线程安全变种类。

3、TreeMap

Entry节点组成的红黑树,红黑树是一个自平衡的排序二叉树,节点值比左边所有子节点的值都大,比右边所有子节点的值都小。

4、HashMap、TreeMap和LinkedHashMap使用场景

首先,这三种数据结构的主要特点如下:

HashMap:增删改查时间复杂度O(1),统计最大最小值时间复杂度O(N)

TreeMap:增删改查统计的时间复杂度O(logN)

LinkedHashMap:时间复杂度同HashMap,但插入顺序和读出顺序一致

所以,使用场景分别如下:

HashMap:适合不要求顺序的增删改查操作

TreeMap:适合基于大小排序的统计操作

LinkedHashMap:适合要求顺序的增删改查操作

5、HashTable

是线程安全的,功能类似于HashMaP,出现的比HashMap要早,现在已经不用了。现在线程安全的都是concurrentHashMap,比Hashtable效率高多了

你可能感兴趣的:(Map数据结构)