HashMap
jdk1.8之前底层是列表散列(数组和链表组合使用),jdk1.8之后是列表散列+红黑树
实现原理
HashMap通过扰动函数得到hash值,经过计算得到要存储的位置,如果当前位置存在元素,判断hash值以及key是否相同,相同则覆盖,不同则通过拉链法解决冲突(为什么要使用扰动函数?扰动函数可以减少碰撞)
线程不安全
可以有一个null键,多个null值
初始容量为6,每次扩容为原来的2倍(当指定初始容量时,初始容量为2的幂次方)
扩容方法resize()在多线程下操作可能导致死循环。jdk1.8已经解决了这个问题
ConcurrentHashMap
线程安全
在 JDK1.7 的时候,Segment(分段锁) 首先将数据分为一段一段的存储,然后给每一段数据配一把锁,当一个线程占用锁访问其中一个段数据时,其他段的数据也能被其他线程访问。JDK1.8 取消了 Segment 分段锁,采用 CAS 和 synchronized 来保证并发安全。数据结构跟 HashMap1.8 的结构类似,数组+链表/红黑二叉树。
要想线程安全,使用这个而不是使用HashTable
HashTable
线程安全
(同一把锁) :使用 synchronized 来保证线程安全,效率非常低下。当一个线程<br>访问同步方法时,其他线程也访问同步方法,可能会进入阻塞或轮询状态
效率低
不能有null键、null值,当put null键值时会抛出空指针异常
初始容量为11,每次扩容为2n+1(当指定初始容量时,初始容量为所指定的容量)