Hashmap是线程安全的吗

不是。Hashmap中的方法是非同步的,并不能直接在多线程并发的环境下直接使用。假如线程A和线程B同时对同一个数组位置调用addEntry,那么这两个线程会同时获得现在的头节点,然后A写入新的头节点之后,B也写入新的头节点,那么B的写入操作会覆盖掉A的写入操作,造成A写入操作的丢失。


Hashmap和Hashtable的区别

  1. 继承不同

    • Hashmap继承自abstractMap
    • Hashtable继承自dictionary
  2. Hashtable是线程安全的,Hashmap不是。

  3. Hashtable中的key和value都不允许出现null值。Hashmap可以,Hashmap允许key可以为null,这样的键只能有一个。但是允许多个key所对应的value为null。

  4. 数组的初始容量大小和容量增长方式不一样

    • Hashtable的数组初始大小为11,增长方式是old*2+1
    • Hashmap的数组初始大小为16,增长方式是翻倍
  5. 计算下标的方式不同

    • Hashtable是h%length
    • Hashmap是h&(length-1)
  6. 哈希值的使用不同

    • Hashtable是直接使用对象的Hashcode
    • Hashmap是重新计算哈希值

Hashmap的初始容量为什么设置为16

  • 首先,length为2的整数次幂的话,h&(length-1)就相当于对length取模,提高了运算效率。
  • 其次,是为了保证散列的均匀性,length为2的整数次幂的话,length-1为奇数,奇数的最后一位是1,h&(length-1)的结果就有可能为奇数,也有可能为偶数,也就是结果的最后一次有可能是0,也有可能是1。这样便保证了散列的均匀性。如果length为奇数,length-1就是偶数,最后一位是0。这样h&(length-1)的结果就只能为偶数,也就是最后一位只能是0,这样任何哈希值都只能被散列在偶数的下标位置上,浪费了近一半的空间。
  • 所以length为2的整数次幂是为了是哈希值发生碰撞的概率更小,散列的更加均匀。

Hashmap之put()方法的执行过程

put()方法执行流程

图片出处见水印