HashMap和HashTable

两者的父类不同

HashMap是继承自AbstractMap类,而HashTable 是继承自Dictionary类.不过他们都实现了Map Cloneable Serializable这三个接口.

对null的支持不同

HashTable:key和value都不能为null

HashMap:key可以为null,但是这样的key只能有一个,因为必须保证key的唯一性;可以有多个key值对应的value为null

安全性不同

HashMap是线程不安全的,在多线程并发的环境下,可能产生死锁等问题,因此需要开发人员自己处理多线程问题.

HashTable是线程安全的,它的每个方法上都有synchronized关键字,因此可以直接用于多线程中.

虽然HashMap不安全,但是它的效率远远高于HashTable,这样设计是合理的,因为大部分的使用场景都是单线程的.当需要多线程操作的时候可以使用线程安全的ConcurrentHashMap.

ConcurrentHashMap虽然也是线程安全的,但是它的效率比HashTable要高好多倍.因为ConcurrentHashMap使用了分段锁,并不多整个数据进行锁定

初始容量大小和每次扩充容量大小不同

HashMap初始化默认的数组大小只有16,自动扩容是翻一倍
HashTable 初始化默认是 11 (除质数球余的分散效果好),自动扩容是两倍+1(奇数)

计算hash值的方法不同

  • HashMap
    static final int hash(Object key) {
        int h;
        return (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16);
    }

上面可以看出key可以为null,key值的hash值的计算方法为:** key的hashCode的高16位不变,低16位与高16位异或的结果作为低16位的结果.(h>>>16,表示无符号右移16位,高位补0)**

  • HashTable
int hash = key.hashCode();
int index = (hash & 0x7FFFFFFF) % tab.length

直接使用key的hashCode,但是为了在hashCode为负数的情况下,取出负数,所以和0x7FFFFFFF (二进制为0111 1111 1111 1111 1111 1111 1111 1111) 负数和其& 操作将产生一个正数.

扩展

分段锁

容器里面有多把锁,每一把锁用于锁容器其中一部分数据,那么当多线程访问容器里面不同数据段的数据时,线程间就不会存在锁竞争,从而有效提高并发访问效率,这就是ConcurrentHashMap所使用的锁分段技术,首先将数据分成一段一段的存储,然后给每一段数据配一把锁,当一个线程占用锁访问其中一段数据的时候,其他段的数据也能被其他线程访问.

posted @ 2020-11-23 21:03  刘指导  阅读(97)  评论(0编辑  收藏  举报