HashMap的底层实现是:数组+链表/红黑树,当某个数组的链表长度达到某个阈值的时候,这个链表就转化为红黑树,这样大大减少了查找时间。
存储查找原理
- 存储:首先获取key的hashCode,然后取模数组的长度,这样可以快速定位到要存储到数组中的坐标,然后判断数组中是否存在元素,如果没有存储,则新建Node节点,把Node节点存储到数组中。如果有元素,则迭代表(红黑二叉树),如果存在此key,默认更新value,不存在则把新构建的Node存储到链表的尾部。
- 查找:同上,获取key的hashcode,通过hashcode取模数组的长度,获取要定位元素的坐标,然后迭代链表,进行每一个元素的equals对比,如果相同则返回该元素。
HashMap线程不安全,Hashtable和ConcurrentHashMap是线程安全的。Hashtable线程安全是因为在每个方法上都添加了synchronized关键字来修饰的,Hashtable是针对整个table的锁定(全表锁),所以在高并发的环境下,多个线程都要竞争同一把锁,导致效率极其低下。
ConcurrentHashMap在JDK1.8以前:采用的是分段锁,具体可以理解为是把一个大的Map拆分为N个小的HashTable,key.hashCode()来决定把key放到哪个Hashtable中。
ConcurrentHashMap中默认是把segments初始化为长度为16的数组。
ConcurrentHashMap在JDK1.8之后:采用CAS和synchronized来保证并发安全。数据结构和HashMap一样 数组+链表+红黑树。