想要说清楚HashMap线程不安全的事情 分两部分
JDK 1.8 以前
- HashMap底层是数组+链表以前人尽皆知了
- 那说一个不是人尽皆知的问题,HashMap放入新元素是采用头插法,什么是头插法呢:
一个数组 Int[] array = {1,2,3,4}
我们想放入一个新的元素0 就是Int[] array = {0,1,2,3,4}
- 再说一个问题 HashMap 是有容量上限的 再超过上限的时候 但凡是一个集合都会开始扩容 当然他也不例外
所以怎么扩容呢
原Map 重新计算放入新的Map 注意这里也是采用头插法 采用头插法会将链表逆序
如:现有两个线程倒班工作 一个链表如下
a—>b—>c–>…—>z
线程1 : 接到需要反转的命令 拿到a 此时他觉得 a后面是b 开始睡觉
线程2 : 1睡觉我干活 我要开始反转了 那么反转后 b后面是a 干累了 我也要睡觉
线程1: 他睡了我接着干 我好像记着 a后面是b -------此时b在梦中说 b后面是a 造成如下情况
a–>b–>a–>…
死循环就此产生 Cpu同志骂骂咧咧的开始嚎叫
JDK 1.8优化
- 此时 头插法变成了尾插法,讲道理肯定不会死循环了吧,确实不会死循环了
- 但是新的问题产生了
还是同样的工作 同样的链表
a—>b—>c–>…—>z
现在要在z后面添加一个 A
此次resize 顺利完成 开始添加新的元素
线程1: 这次我在后面加 刚要加A 他困了 遂放心开始睡觉
线程2: 我要加个B 然后链表变成了
a—>b—>c–>…—>z–>B
然后线程2放心的睡觉了
线程1:醒了干活 z后面应该放A 此时链表变成了
a—>b—>c–>…—>z–>A
线程2: ???? 我的B呢?
B丢了哇~~
以上就是HashMap线程不安全的部分原因