Java后端八股笔记2 Java集合

16 阅读2分钟

List

名称实现线程安全说明
ArrayList数组,扩容时建立更大的数组,并把数据复制到新数组
新容量扩大为原容量的1.5倍
快速随机访问,但增删慢
LinkedList双向列表随机访问慢,增删快
Vector内部为对象数组,扩容方法同ArrayList安全内部方法使用synchronized修饰
线程安全导致开销大
CopyonWriteArraylist数组安全使用volatile关键字修饰数组
写入操作时,加上互斥锁,首先将原数组拷贝一份并大小+1,并将新元素放入新数组最后一位,最后用新数组的地址替换就数组的地址。
在替换前读就数组,替换后读新数组
读操作不加锁

Map

实现线程安全说明
HashMap数组+链表(Java8后为红黑树)链表超过阈值就变成红黑树
LinkedHashMap继承自HashMap,使用双向列表
TreeMap红黑树可以对键进行排序,默认按照自然排序
Hashtable同HashMap安全Java早期实现线程安全
方法使用synchronized关键词修饰

解决哈希冲突的方法

  • 拉链法
  • 开放寻址法:找到另一个可用位置
  • 再哈希法:用另一个哈希函数进行计算
  • 扩容

HashMap的put过程

  1. 通过哈希函数进行计算得到存放位置
  2. 存放位置是否为空?为空则创建一个Entry对象并放入
  3. 不为空则判断是否与put的key一致?key相等但value不一样则替换为新的value
  4. key不一样,则遍历链表或红黑树寻找是否存在相同的键,存在则同上
  5. 均不同则将新的键值对加在链表头
  6. 检查链表长度是否达到阈值(默认为8),达到则转化为红黑树
  7. 检查是否达到负载阈值(默认为0.75),到达则进行扩容:创造原数组大小二倍的新数组,并对其中元素进行重新计算哈希码并分配位置,更新数组引用

ConcurrentHashMap实现

分段锁:JDK1.7使用数组+链表,将ConcurrentHashMap分为16个Segment(继承自ReentrantLock),扮演锁的角色,每个segment中有一个HashEntry数组用于存放数据

format,webp.webp JDK1.8:通过volatile+CAS实现

  • 若为空,则使用CAS原子插入
  • 若不为空,则使用synchronized方法锁定链表头结点,开始遍历链表并进行操作

PriorityQueue

Set

实现线程安全
HashSetHashMap,key为HashSet存储的值,value为统一的名为PRESENT的Object类型常量
LinkedHashSet继承自HashSet,通过LinkedHashMap实现,使用双向链表维护元素插入顺序
TreeSetTreeMap