List
| 名称 | 实现 | 线程安全 | 说明 |
|---|---|---|---|
ArrayList | 数组,扩容时建立更大的数组,并把数据复制到新数组 新容量扩大为原容量的1.5倍 | 非 | 快速随机访问,但增删慢 |
LinkedList | 双向列表 | 非 | 随机访问慢,增删快 |
Vector | 内部为对象数组,扩容方法同ArrayList | 安全 | 内部方法使用synchronized修饰 线程安全导致开销大 |
CopyonWriteArraylist | 数组 | 安全 | 使用volatile关键字修饰数组 写入操作时,加上互斥锁,首先将原数组拷贝一份并大小+1,并将新元素放入新数组最后一位,最后用新数组的地址替换就数组的地址。 在替换前读就数组,替换后读新数组 读操作不加锁 |
Map
| 实现 | 线程安全 | 说明 | |
|---|---|---|---|
HashMap | 数组+链表(Java8后为红黑树) | 非 | 链表超过阈值就变成红黑树 |
LinkedHashMap | 继承自HashMap,使用双向列表 | 非 | |
TreeMap | 红黑树 | 非 | 可以对键进行排序,默认按照自然排序 |
Hashtable | 同HashMap | 安全 | Java早期实现线程安全 方法使用synchronized关键词修饰 |
解决哈希冲突的方法
- 拉链法
- 开放寻址法:找到另一个可用位置
- 再哈希法:用另一个哈希函数进行计算
- 扩容
HashMap的put过程
- 通过哈希函数进行计算得到存放位置
- 存放位置是否为空?为空则创建一个Entry对象并放入
- 不为空则判断是否与put的key一致?key相等但value不一样则替换为新的value
- key不一样,则遍历链表或红黑树寻找是否存在相同的键,存在则同上
- 均不同则将新的键值对加在链表头
- 检查链表长度是否达到阈值(默认为8),达到则转化为红黑树
- 检查是否达到负载阈值(默认为0.75),到达则进行扩容:创造原数组大小二倍的新数组,并对其中元素进行重新计算哈希码并分配位置,更新数组引用
ConcurrentHashMap实现
分段锁:JDK1.7使用数组+链表,将ConcurrentHashMap分为16个Segment(继承自ReentrantLock),扮演锁的角色,每个segment中有一个HashEntry数组用于存放数据
JDK1.8:通过volatile+CAS实现
- 若为空,则使用CAS原子插入
- 若不为空,则使用synchronized方法锁定链表头结点,开始遍历链表并进行操作
PriorityQueue
Set
| 实现 | 线程安全 | |
|---|---|---|
HashSet | HashMap,key为HashSet存储的值,value为统一的名为PRESENT的Object类型常量 | 非 |
LinkedHashSet | 继承自HashSet,通过LinkedHashMap实现,使用双向链表维护元素插入顺序 | 非 |
TreeSet | TreeMap | 非 |