HashTable
底层是通过数组加链表实现,无论key还是value都不能为null,线程安全,实现线程安全的方式是在修改数据时锁定整个hashTable,效率低ConcurrentHashMap做了相关优化
初始长度为11 扩容为 旧长度*2+1
HashMap
底层数组加链表实现,可以存储null键和null值,线程不安全
初始长度为16 扩容是旧长度*2,长度一定为2的n次幂
扩容针对整个map,每次扩容时,原来数组中的元素依次重新计算存放位置,重新插入
插入元素后才会判断是否应该扩容,如果扩容后不插入数据可能造成无效扩容
如果希望加快key查找的时间,科技降低负载因子,加大初始大小,减少冲突的概率,设置长度时需要根据我们的数据大小来计算长度 预估大小/负载因子
ConcurrentHashMap
底层采用分段的数组+链表实现,线程安全
通过把整个map分为n个Segment,可以提供相同的线程安全,但是效率提升n倍,默认提升16倍.(对concurrentHashMap执行读操作时,不会加锁,因为HashEntry的value是volatile的,也能保证读取到最新的值);
HashTable的synchronized是针对整张hash表,每个线程进来都会独占表,concurrentHashMap采用了分段锁技术
有些方法需要跨段,比如size()和containsValue(),它会按顺序锁定分段执行完成后按顺序解锁
扩容:当分段内内容超过75%时触发扩容,不会对整个map扩容,而且会在插入前检测扩容,有效避免无效扩容
HashMap中可以用null作为键,但是只有一个,值可以重复
当get("key")返回值为null时,并不能缺点hashmap中没有这个key,因为null也可以作为值
所以判断key是否存在使用containsKey();在hashtable中无论是key还是value都不能为null
HashTable是线程安全的,它的方法是同步的,HashMap需要手动同步
ConcurrentHashMap默认将hash表分为了16段,每个线程使用时只会锁住自己需要的分段,并发性能提升很大,读操作是不加锁的,hashtable的读操作是加锁的