面试题:
1、HashMap的线程安全吗?有哪些替代方案
HashMap不安全,HashMap的初始容量是16,当长度超出12(16的3/4)时,Map需要扩容,每次扩容之后大小都是之前的两倍。
扩容时,需要将容器中的元素重新计算一遍,并且创建一个更长的新的数组,将元素复制进这个新数组。这个步骤很消耗性能,所以,在初始化map的时候,尽可能地按照需要指定其长度,尽量减少resize的次数,这是一个良好的习惯。
1)为什么采用两倍的扩容方式呢?
因为使用位运算比直接取模效率高很多,在JDK7中,采用的是取模来计算桶的位置,在JDK8中采用了巧妙的位运算的方式:h&(length-1),h是元素的key的哈希值,length是数组的长度。这样的好处是首先降低了运算的难度,因为位运算对于计算机来说只要判断1或0;第二点好处是,由于这种方式,在HashMap扩容的时候,不需要重新对hash值进行取模。只需要判断当前元素是保持当前位置不变,还是需要移动长度为length个位置即可,这减少了运算的次数。
2)两个线程同时执行resize操作,先来演示一下假如在单线程情况下,正确的扩容流程的图解: