HashMap线程不安全的场景

put
多个线程同时向Node[]的同一个位置插入时,会发生覆盖,只有一个线程的操作会被保留。
如下图源码,假如有A、B两个线程,同时在执行put且数组下标都为1,两个线程同时运行到第一个红框位置,判断tab[1]为null,A线程先执行tab[1]=NodeA,B线程再执行tab[1]=NodeB,这样B线程的操作就会覆盖A线程的。
第二个红框位置也会导致类似的问题,只不过是发生在链表上,而不是Node[]上

 

 

resize + get
如果多个线程同时触发扩容resize,可能会形成环形链表,然后在调用get()获取一个不存在的元素时会发生死循环,导致CPU100%,JDK8已经解决了此问题。
主要原因就是,JDK7在Hash冲突时采用头插法,扩容时若旧链表的元素还会Hash到同一个新链表,那么新链表与旧链表的顺序是反的(从 A-> B变成了B -> A),在1.8后采用尾插法就不会出现这种问题,同时1.8的链表长度如果大于8就会转变成红黑树。

size
由于++size、--size不是原子性操作,所以也会导致数据不一致。

posted @ 2021-06-24 13:27  郭慕荣  阅读(294)  评论(0编辑  收藏  举报