本文章涉及到JDK1.7的HashMap原理,重复的内容不再过多赘述,如果没有学过的同学可以看下面这篇文章:HashMap底层原理的深入了解(JDK1.7和JDK1.8对比)
大家都知道ConcurrentHashMap是线程安全的,而HashMap是线程不安全的
那么HashMap为什么是线程不安全的呢?
我们假设有两个线程同时对一个HashMap进行put操作;
那么它们两个线程都会基于put的流程去进行hashCode的运算以及index下标的计算;
但是有可能这两个线程put的元素的key计算出来的下标是相同的,在正常情况下它们会在这个下标下面形成一个链表,然后插入到链表中,但是在HashMap中它会先去判断数组的当前位置是否为空;为空则放在当前索引位置,如果不为空则加到链表中;
那么如果在多线程的情况下呢?
假设这两个线程同时判断当前线程位置是否为空,得到的结果都为空,那么这两个线程会把各自生成的Entry对象放到这个索引位置来,那么其中有一条数据一定会被另外一条数据所覆盖,造成数据的丢失,这就是为什么HashMap线程不安全的原因;
那么对于这种情况我们可以怎么解决?
1.HashTable
HahsTable在put方法的前面加了synchronized锁,也就是说多个线程对同一个HashTable进行put方法的时候,只有一个线程能够拿到锁进行后续操作,而没有拿到锁的线程就只有等着,等拿到锁之后再进行操作;
存在的问题:
锁的粒度太大了,如果线程没有拿到锁,那么它就没有执行put方法的资格,如果说两个线程计算出来的index其实是不同的,完全可以进行并发添加,互不影响,但是因为锁的粒度太大,不能并发执行,因此效率和性能都很差;
2.ConcurrentHashMap
它是HashMap的子类,在HashEntry数组外面又嵌套了一层Segment数组
并且采用了分段锁和CAS机制,让锁的粒度更细,性能更高
因此在后续的源码解读中,会着重上面的部分去进行分析,注重锁的处理,以及它内部一些优雅的设计让性能更高