天天看点

HashMap和ConcurrentHashMap的浅析HashMap和ConcurrentHashMap的浅析

HashMap和ConcurrentHashMap的浅析

HashMap的内部数据结构

不同的JDK实现方式不同

JDK1.6、1.7中:位桶+链表

首先它是一个数组实现,其解决冲突的方式为开链法。即多个元素hashCode相同时,放在链表里。如下图所示。

HashMap和ConcurrentHashMap的浅析HashMap和ConcurrentHashMap的浅析

JDK1.8中:位桶+链表+红黑树

上面方式的缺点是,当相同hashCode的元素比较多时,单链表的查询效率比较低。由于,当某个单链表的个数达到一个数目(默认8)时,就采用红黑树的数据结构。

当加载因子达到0.75时,就会将位桶的长度增加一倍,然后将原有的数据拷到新的位桶中。

HashMap和ConcurrentHashMap

显然HashMap是非线程安全的。

而ConcurrentHashMap是线程安全的,一般情况下,在需要用到线程安全的场景下时,ConcurrentHashMap是第一选择。

ConcurrentHashMap相比较于HashTable的好处是啥?

HashTable是全表的锁,即一个线程在写的时候,另一个线程就不允许写了。不管他们写的是哪个key。

而ConcurrentHashMap也是锁,只是锁的粒度不同。即把整个数组分为多个段(Segment),锁只是针对每个段进行。即一个线程在写段1,另一个线程是可以写段2的。如图:

HashMap和ConcurrentHashMap的浅析HashMap和ConcurrentHashMap的浅析

还是很容易理解的。

存在的问题:

有些操作是跨段的,这就需要进行锁住整张表。这里就会按照段的顺序进行逐步加锁,直至锁住整张表,操作完毕后,再按照顺序释放所有锁。注意这里的“顺序是很重的”,保证顺序性才能防止死锁的产生。

为什么?这里就多说一点。为何顺序加锁就不会导致死锁?

“顺序的申请和释放资源”其实就是防止死锁的一个很重要的解决方法。

我们来分析一下:

死锁的产生的场景:A线程占6申请7,B线程占7申请6,这样就会产生死锁。而如果我们都按照顺序的大小申请资源。即B线程占7之后,就一定不会申请比7小的资源。这样就不会产生死锁了。

其实死锁相关的知识还是比较多的,这里只是大概说一下。