Java基础知识2:集合扩容机制(1)

1. ArrayList源码&扩容机制分析

1.1 概念

ArrayList的底层是动态数组,即数组的大小能够改变,随着存储越来越多元素,容量会随之改变。

1.2. 根据ArrayList的初始化方式,扩容也不同方式

ArrayList有三种构造器,每种构造器有不同的扩容机制
1) 无参构造器,无参构造
2)有参构造器,传容量构造
3) 有参构造器,传列表构造

1.3. ArrayList的扩容机制

1)第一种情况:当ArrayList的容量为0时,此时添加元素的话,需要扩容,三种构造方法创建的
(1) 无参构造,创建ArrayList后容量为0,添加第一个元素后,容量变为10,此后若需要扩容,则正常扩容。
(2) 传容量构造,当参数为0时,创建ArrayList后容量为0,添加第一个元素后,容量为1,此时ArrayList是满的,下次添加元素时需正常扩容。
(3) 传列表构造,当列表为空时,创建ArrayList后容量为0,添加第一个元素后,容量为1,此时ArrayList是满的,下次添加元素时需正常扩容。
2)第二种情况,当ArrayList的容量大于0,并且ArrayList是满的时,此时添加元素的话,进行正常扩容,每次扩容到原来的1.5倍(新=旧+旧/2)。

2. HashMap源码&底层数据结构分析

2.1 HashMap的结构

  1. 数据结构:HashMap核心是数组+链表/红黑树的形式
  2. 链表和红黑树都是为了解决hash冲突而存在。
  3. 线程安全与否:HashMap是线程不安全的,ConcurrentHashMap才是线程安全的。

2.1 哈希冲突和扩容

  1. 哈希冲突(1.7版本):当对每一个添加元素,经过哈希函数分配好位置时,如果原来已经存在数据,那么就以拉链法添加到链表尾端;
  2. 哈希冲突(1.8版本):当对每一个添加元素,经过哈希函数分配好位置时,如果原来已经存在数据:
    1)如果链表长度小于8;那么就以拉链法添加到链表尾端;
    2)如果链表的长度大于8数组长度也大于64,那么就把链表转化为红黑树;
    3)如果链表大于8,数组长度也小于64,那么就进行扩容。
  3. 扩容机制
    1)HashMap的初始容量为16,那么每一次快要满了之后,都是*2操作。 总是使用 2 的幂作为哈希表的大小(为了更加方便的计算hash值)

3. ConcurrentHashMap源码&底层数据结构分析

3.1版本1.7

1)使用分段锁,有若干个segment;
2)每个segment中有一个hashentry数组,类似于hashmap能够使用;
3)对每个Segment进行加锁,Segment 继承了 ReentrantLock;故最多可以有16个线程并发执行

3.2 版本1.8

Node 数组 + 链表 / 红黑树。当冲突链表达到一定长度时,链表会转换成红黑树
ConcurrentHashMap 使用的 Synchronized 锁CAS 的机制
1)利用CAS和volatile进行初始化安全操作
2)通过 synchronized 进行写数据put操作。

3.3 两者对比

1)1.7 有多个Node,对每个node都需要进行加锁操作
2)1.8只有一个Node
3)锁的粒度从多个Node级别又减小到一个Node级别,再度减小锁竞争减小程序同步的部分

参考文献
JavaGuide

猜你喜欢

转载自blog.csdn.net/qq_42974034/article/details/124061524
今日推荐