hashmap线程安全吗
640
hashmap非线程安全,其线程不安全主要体现在1、JDK1.7并发执行扩容操作时会造成环形链和数据丢失;2、JDK1.8并发执行put操作时会发生数据覆盖。HashMap的扩容操作会重新定位每个桶的下标,并采用头插法将元素迁移到新数组中。头插法是造成死循环和数据丢失的关键。
1、JDK1.7并发执行扩容操作时会造成环形链和数据丢失
HashMap的扩容操作(先扩容在头插法插入)会重新定位每个桶的下标,并采用头插法将元素迁移到新数组中。头插法会将链表的顺序翻转,这也是造成死循环和数据丢失的关键。
JDK1.7的时候采用头插法,多线程同时插入的时候,A线程在插入节点B,B线程也在插入,遇到容量不够开始扩容,重新hash,放置元素,采用头插法,后遍历到的B节点放入了头部,这样形成了环。
2、JDK1.8并发执行put操作时会发生数据覆盖
JDK1.7出现的问题,在JDK1.8中已经得到了很好的解决,JDK1.8直接在resize函数中完成了数据迁移。在进行元素插入时使用的是尾插法然后在扩容。但是以下两种情况造成线程不安全:
- 两个线程同时插入只有一个成功插入;
- 可能会造成两次resize(++size>threshold) 。
拓展阅读
如何解决hashmap的线程不安全性
- 使用HashTable(效率比较差)
- 使用ConcurrentHashMap(比较常用的)
- 使用Collections.synchronizedMap()